| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> C++知识库 -> Item 26: Avoid overloading on universal references. -> 正文阅读 |
|
[C++知识库]Item 26: Avoid overloading on universal references. |
Item 26: Avoid overloading on universal references.Effective Modern C++ Item 26 的学习和解读。 这一节给出的建议是尽量不要对万能引用参数的函数进行重载,根因是重载函数的匹配规则。先从一个例子说起:
上面的代码,我们看3个调用:
第一个调用:logAndAdd 的参数 name 被绑定到一个左值 petName 上。由于 name 是一个左值,names.emplace(name) 将发生一次拷贝。 第二个调用:std::string(“Persephone”) 首先会显示构造出一个临时的 std::string,并且是一个右值。name 被绑定到一个右值,但是 name 是一个左值,names.emplace(name) 将发生一次拷贝。 第三个调用:“Patty Dog” 传入 logAndAdd 将隐式构造出一个临时的 std::string,并且是一个右值。name 被绑定到一个右值,但是 name 是一个左值,names.emplace(name) 将发生一次拷贝。 后面两个调用点, name 都是绑定到一个右值,我们可以通过移动来代替拷贝来提高性能,我们很容易使用万能引用重写 logAndAdd 如下:
现在,步入本节的主题。对于上述代码,假设在 logAndAdd 内部需要根据一个索引查找 name,logAndAdd 被重载成这样:
新增一个 int 类型参数的调用方式:
以上还没什么问题,一切都还符合我们的预期。但是,考略下面的调用场景:
对于 short 类型的 nameIdx,我们期望的显示是调用 int 类型的 logAndAdd 重载。但事实却是这样:万能引用版本的 T 将被推导成 short,因而产生一个确切的匹配版本,然后在 names.emplace 时候会用 short 类型去构造 std::string,显然会报错。 在 C++ 中,以万能引用为参数的函数是最贪婪的函数,它能实例化出多数能够胜任的精确匹配版本,而这个例子中 short 需要做类型转换成 int 类型才会匹配到 int 类型的 logAndAdd。而 C++ 重载函数的匹配原则:如果模板实例化出的函数和普通重载函数都精确匹配,则优先选择普通重载函数,其次选择模板函数实例化出来的精确版本。因此这里会匹配到万能引用实例化出的版本。 再看万能引用构造函数的例子:
这里会有两个问题。首先,传一个除 int 外的整形类型(比如,std::size_t, short, long)将不会调用 int 版本的构造函数,而是调用万能l引用版本的构造函数,然后这将导致编译失败。然后还有一个更加糟糕的问题,根据 Item 17: Understand special member function generation. 介绍我们知道编译器将在合适的条件下生成 copy 和 move 类构造函数。Person 实际可能是下面这个样子:
考略下面的调用:
使用 p 去创建一个新的 Person,这里不会调用 Person 的拷贝构造函数,而会调用完美转发构造函数。这是因为 Person 的拷贝构造函数的参数是一个 const 类型的 ,而 p 是一个非 const 类型,并且完美转发构造函数会实例化出一个精确的匹配版本。当我们稍微改造下 p,就可以调用编译器生成的拷贝构造函数:
虽然完美转发构造函数也能实例化出一个精确函数签名的版本,但是 C++ 重载匹配会选择普通的重载版本。 当继承介入进来之后,问题将变得更加让人无法接受,我们看下这样的代码片段:
这两个构造函数都会调用基类的完美转发构造函数,因为这两个构造函数给基类传入的都是 SpecialPerson 类型的参数,完美转发构造函数会实例化出精确匹配的版本,最后代码将无法编译通过。 总之,对万能引用参数函数进行重载是一个糟糕的设计,我们需要尽量避免。 |
|
C++知识库 最新文章 |
【C++】友元、嵌套类、异常、RTTI、类型转换 |
通讯录的思路与实现(C语言) |
C++PrimerPlus 第七章 函数-C++的编程模块( |
Problem C: 算法9-9~9-12:平衡二叉树的基本 |
MSVC C++ UTF-8编程 |
C++进阶 多态原理 |
简单string类c++实现 |
我的年度总结 |
【C语言】以深厚地基筑伟岸高楼-基础篇(六 |
c语言常见错误合集 |
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/23 23:42:35- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |