Jen*_*aKh 5 c++ aggregate language-lawyer value-initialization c++11
我尝试了解@bolov对已删除默认构造函数问题的第一个公认答案。仍然可以创建对象...有时 [1]
似乎我在那儿发现了一个错误,因此弄乱了整个解释。
@bolov解释了为什么此代码成功用c ++ 11编译:
方案A
struct foo {
foo() = delete;
};
// All bellow OK (no errors, no warnings)
foo f = foo{};
foo f = {};
foo f{}; // will use only this from now on.
Run Code Online (Sandbox Code Playgroud)
以及为什么此代码无法在c ++ 11中编译:
方案C
struct foo {
foo() = delete;
foo(int) {};
};
foo f{}; // error call to deleted constructor
Run Code Online (Sandbox Code Playgroud)
他说,关键是第一个foo是集合,而第二个foo不是集合。
然后他给出了cppreference的摘录:
T类型的对象的列表初始化的影响是:...
- 如果T是聚合类型,则执行聚合初始化。这照顾了场景ABDE(以及C ++ 14中的F)
否则,将分两个阶段考虑T的构造函数:
所有采用std :: initializer_list的构造方法...
否则,T的所有构造函数都将参与重载解析[...],这将照顾到C(和C ++ 11中的F)...
根据摘录,当你写foo f {}; 在方案A中,您将进行聚合初始化。那就太好了。但是实际上在c ++ 11(#3337草案,最接近标准)中,您具有不同的初始化顺序:
对象或类型T的引用的列表初始化定义如下:
- 如果初始化器列表中没有元素,并且T是具有默认构造函数的类类型,则该对象将被值初始化。
- 否则,如果T是一个聚合,则执行聚合初始化(8.5.1)
所以foo f {}; 在方案A中应导致值初始化,即将调用DELETED默认构造函数,并且代码应无法编译。
由于核心问题 1301(这是针对 C++11 的缺陷),列表初始化的优先级更改为:
T 类型的对象或引用的列表初始化定义如下:
- 如果初始值设定项列表没有元素并且 T 是具有默认构造函数的类类型,则该对象将被值初始化。
- 否则,如果 T 是聚合,则执行聚合初始化 (8.5.1)
到:
T 类型的对象或引用的列表初始化定义如下:
- 如果 T 是聚合,则执行聚合初始化 (8.5.1)
- 否则,如果初始化列表没有元素并且 T 是具有默认构造函数的类类型,则该对象将被值初始化。
所以foo{}
场景A中仍然是聚合初始化。