我试着理解@bolov对Deleted default constructor. Objects can still be created... sometimes [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.
为什么这段代码在C ++ 11中编译失败:
情景C
struct foo {
foo() = delete;
foo(int) {};
};
foo f{}; // error call to deleted constructor
他说重点是第一个foo是聚合,第二个foo不是聚合。
然后他给出了cppreference的摘录:
类型T对象的列表初始化的效果是: ...
- 如果T是聚合类型,则执行聚合初始化。这将处理场景A B D E(和C ++ 14中的F)
否则,T的构造函数分为两个阶段:
- 的构造函数
所有采用std :: initializer_list ...
否则[...] T的所有构造函数都参与重载决策[...]这将照顾C(和C ++ 11中的F) ...
根据您在方案A 中编写 foo f {}; 的摘录,您将获得聚合初始化。这会很棒。但实际上在c ++ 11(#3337草案,最接近标准)中你有不同的初始化顺序:
对象或类型T的引用的列表初始化定义如下:
- 如果初始化列表没有元素且T是具有默认构造函数的类类型,则该对象是值初始化的。
- 否则,如果T是聚合,则执行聚合初始化(8.5.1)
场景A 中的 foo f {}; 应该导致值初始化,也就是说,将调用DELETED默认构造函数并且代码不能成为编译。
答案 0 :(得分:3)
由于Core Issue 1301是针对C ++ 11的缺陷,列表初始化的优先级从以下变为:
对象或类型T的引用的列表初始化定义如下:
- 如果初始化列表没有元素且T是具有默认构造函数的类类型,则该对象是值初始化的。
- 否则,如果T是聚合,则执行聚合初始化(8.5.1)
为:
对象或类型T的引用的列表初始化定义如下:
- 如果T是聚合,则执行聚合初始化(8.5.1)
- 否则,如果初始化列表没有元素且T是具有默认构造函数的类类型,则该对象是值初始化的。
因此,场景A中的foo{}
仍然是聚合初始化。