复制列表初始化是否在概念上调用复制 ctor
Does copy list initialization invoke copy ctor conceptually?
在C++11之前,我们可以通过编写类似A a = 1;
的东西来进行复制初始化,它或多或少等同于A a = A(1);
。也就是说,首先创建一个临时,然后调用一个副本 ctor。无论复制省略如何,这都必须在概念上如此,并且复制 ctor 必须是可访问的。
使用 C++11 中的列表初始化,我们可以通过编写 A a = {1, 2};
来进行复制列表初始化。在我看来,这应该或多或少等同于A a = A(1, 2);
.但是,在 GCC 和 clang 上,即使无法访问复制和移动 ctor(通过声明为私有),A a = {1, 2}
也会编译。尽管如此,如果无法访问相应的复制/移动 ctor,A a = 1;
不会在 GCC 或 clang 上编译。因此,A a = {1, 2};
似乎或多或少等同于直接列表初始化A a{1, 2};
。这与真正的直接列表初始化之间的区别在于,如果采用两个整数的 ctor 是显式的,则A a = {1, 2};
不会编译。在这方面,A a = {1, 2};
类似于副本初始化。
所以,我的问题是:A a = {1, 2};
概念上的表达的确切语义是什么?从概念上讲,复制省略不会妨碍。
该标准很好地描述了它;[dcl.init.list]/3:
类型为
T
的对象或引用的列表初始化定义如下:
- [...]
- 否则,如果
T
是类类型,则考虑构造函数。这 枚举适用的构造函数并选择最佳构造函数 通过重载解析(13.3、13.3.1.7)。如果变窄 转换(见下文)是转换任何参数所必需的, 程序格式不正确。
[over.match.list](强调我的):
因此,如果未找到初始值设定项列表构造函数当非聚合类类型的对象
T
进行列表初始化时 (8.5.4),重载解析分两个阶段选择构造函数:
最初,候选函数是类
T
的初始值设定项列表构造函数 (8.5.4),参数列表由 初始值设定项列表作为单个参数。如果未找到可行的初始值设定项列表构造函数,则再次执行重载解析,其中候选函数均为 类的构造函数
T
和参数列表由 初始值设定项列表的元素。如果初始值设定项列表没有 元素和 T 有一个默认构造函数,第一阶段被省略。
在复制列表初始化中,如果选择了explicit
构造函数,则 初始化格式不正确。
(如您的情况所示),则初始值设定项列表的元素构成构造函数调用的参数。事实上,直接列表初始化和复制列表初始化的唯一区别是由最后一个粗体句子涵盖的。
这是列表初始化的优点之一:它不需要存在无论如何都不会使用的特殊成员函数。
- 当从函数参数中的临时值调用复制构造函数时
- 使用仅使用一次的变量调用的复制构造函数.这可能是通过调用move构造函数进行编译器优化的情况吗
- 为什么类中的ostringstream类型的成员会导致";调用隐含删除复制构造函数";错误
- 为什么默认复制函数在按值发送参数时不调用?
- 为什么调用复制构造函数而不是移动构造函数?
- C++ 基本 CTOR 说明 - 为什么不调用赋值/复制构造函数
- 为用户定义的类正确调用复制构造函数/赋值运算符
- 复制构造函数中的递归调用
- 编译器调用复制运算符而不是移动运算符
- 为什么我的运算符 + 重载尽管是通过引用传递的,但仍调用我的复制构造函数?
- 使用 pybind11 调用 Python 函数时避免复制输入数据
- 为什么没有调用此模板类的复制构造函数?
- 为什么当我做复制和交换习语时不调用我的复制构造函数?
- std::async 如何工作:为什么它会调用这么多次复制/移动?
- 调用类模板中隐式删除的复制构造函数
- 我不知道为什么复制构造函数的调用在 c++ 中不稳定
- push_back std::vector,则重复调用复制构造函数
- 减少复制构造函数调用
- 调用值构造函数而不是复制构造函数
- 向量<shared_ptr<X>>复制- 调用 X 构造函数?