C++备忘录005:重载:引用、拷贝、移动和perfect forwarding,谁被调用了?

本文主要是介绍C++备忘录005:重载:引用、拷贝、移动和perfect forwarding,谁被调用了?,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

重载函数的调用优先级问题非常?疼,但是正如Nicolai Josuttis所说:C++允许你把性能追求到极至,但这是有代价的。

(午夜梦回的时候,我经常问自己这代价是不是太过高昂了?)

看下面的简单例子

struct X {};void foo(const X &) {std::cout << "const X &\n";
}auto bar() {return X{};
}

foo没有重载,只接受“传统“的参数类型const &

还有main中几种调用情况的打印

int main() {const auto out = [width=20, &os=std::cout](const char * const tag){os << std::setw(width) << tag << ' ';};auto x = X{};const auto cx = X{};out("foo(x)");foo(x);out("foo(cx)");foo(cx);out("foo(X{})");foo(X{});out("foo(bar())");foo(bar());out("foo(std::move(x))");foo(std::move(x));
}

程序的输出是

              foo(x) const X &foo(cx) const X &foo(X{}) const X &foo(bar()) const X &foo(std::move(x)) const X &

没什么值得吃惊的,我们然后再加一个重载

void foo(X &&) {std::cout << "X &&\n";
}

然后输出变成了,

              foo(x) const X &foo(cx) const X &foo(X{}) X &&foo(bar()) X &&foo(std::move(x)) X &&

因为foo(x)foo(cx)中,参数都是lvalue,所以匹配foo(const &),然后X{}bar()std::move(x)都是rvalue,所以匹配foo(X &&)

我们再加一个perfect forwarding

template <typename T, typename = std::enable_if_t<std::is_constructible_v<X, T>>>
void foo(T &&) {std::cout << "T &&\n";
}

然后输出变成了

              foo(x) T &&foo(cx) const X &foo(X{}) X &&foo(bar()) X &&foo(std::move(x)) X &&

foo(x)的匹配从foo(const &)变成了模版??!

这是因为foo(T&&)这里能够匹配一切引用,x是非const类型,所以相比foo(const &)来说,foo(T&&)实例化的foo(&),对foo(x)来说是更精确的匹配

我们可以进一步验证以下,增加一个重载

void foo(X &) {std::cout << "X &\n";
}

输出变成了

              foo(x) X &foo(cx) const X &foo(X{}) X &&foo(bar()) X &&foo(std::move(x)) X &&

此时,foo(x)优先匹配了foo(&),而不是模版

这篇关于C++备忘录005:重载:引用、拷贝、移动和perfect forwarding,谁被调用了?的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1023461

相关文章

C++中unordered_set哈希集合的实现

《C++中unordered_set哈希集合的实现》std::unordered_set是C++标准库中的无序关联容器,基于哈希表实现,具有元素唯一性和无序性特点,本文就来详细的介绍一下unorder... 目录一、概述二、头文件与命名空间三、常用方法与示例1. 构造与析构2. 迭代器与遍历3. 容量相关4

C++中悬垂引用(Dangling Reference) 的实现

《C++中悬垂引用(DanglingReference)的实现》C++中的悬垂引用指引用绑定的对象被销毁后引用仍存在的情况,会导致访问无效内存,下面就来详细的介绍一下产生的原因以及如何避免,感兴趣... 目录悬垂引用的产生原因1. 引用绑定到局部变量,变量超出作用域后销毁2. 引用绑定到动态分配的对象,对象

Python内存管理机制之垃圾回收与引用计数操作全过程

《Python内存管理机制之垃圾回收与引用计数操作全过程》SQLAlchemy是Python中最流行的ORM(对象关系映射)框架之一,它提供了高效且灵活的数据库操作方式,本文将介绍如何使用SQLAlc... 目录安装核心概念连接数据库定义数据模型创建数据库表基本CRUD操作创建数据读取数据更新数据删除数据查

C++读写word文档(.docx)DuckX库的使用详解

《C++读写word文档(.docx)DuckX库的使用详解》DuckX是C++库,用于创建/编辑.docx文件,支持读取文档、添加段落/片段、编辑表格,解决中文乱码需更改编码方案,进阶功能含文本替换... 目录一、基本用法1. 读取文档3. 添加段落4. 添加片段3. 编辑表格二、进阶用法1. 文本替换2

MyBatis/MyBatis-Plus同事务循环调用存储过程获取主键重复问题分析及解决

《MyBatis/MyBatis-Plus同事务循环调用存储过程获取主键重复问题分析及解决》MyBatis默认开启一级缓存,同一事务中循环调用查询方法时会重复使用缓存数据,导致获取的序列主键值均为1,... 目录问题原因解决办法如果是存储过程总结问题myBATis有如下代码获取序列作为主键IdMappe

C++中处理文本数据char与string的终极对比指南

《C++中处理文本数据char与string的终极对比指南》在C++编程中char和string是两种用于处理字符数据的类型,但它们在使用方式和功能上有显著的不同,:本文主要介绍C++中处理文本数... 目录1. 基本定义与本质2. 内存管理3. 操作与功能4. 性能特点5. 使用场景6. 相互转换核心区别

Java中实现对象的拷贝案例讲解

《Java中实现对象的拷贝案例讲解》Java对象拷贝分为浅拷贝(复制值及引用地址)和深拷贝(递归复制所有引用对象),常用方法包括Object.clone()、序列化及JSON转换,需处理循环引用问题,... 目录对象的拷贝简介浅拷贝和深拷贝浅拷贝深拷贝深拷贝和循环引用总结对象的拷贝简介对象的拷贝,把一个

使用Go调用第三方API的方法详解

《使用Go调用第三方API的方法详解》在现代应用开发中,调用第三方API是非常常见的场景,比如获取天气预报、翻译文本、发送短信等,Go作为一门高效并发的编程语言,拥有强大的标准库和丰富的第三方库,可以... 目录引言一、准备工作二、案例1:调用天气查询 API1. 注册并获取 API Key2. 代码实现3

C++右移运算符的一个小坑及解决

《C++右移运算符的一个小坑及解决》文章指出右移运算符处理负数时左侧补1导致死循环,与除法行为不同,强调需注意补码机制以正确统计二进制1的个数... 目录我遇到了这么一个www.chinasem.cn函数由此可以看到也很好理解总结我遇到了这么一个函数template<typename T>unsigned

C++统计函数执行时间的最佳实践

《C++统计函数执行时间的最佳实践》在软件开发过程中,性能分析是优化程序的重要环节,了解函数的执行时间分布对于识别性能瓶颈至关重要,本文将分享一个C++函数执行时间统计工具,希望对大家有所帮助... 目录前言工具特性核心设计1. 数据结构设计2. 单例模式管理器3. RAII自动计时使用方法基本用法高级用法