聚集初始化之前的c ++ 11值初始化

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默认构造函数,并且代码应无法编译。

Bar*_*rry 3

由于核心问题 1301(这是针对 C++11 的缺陷),列表初始化的优先级更改为:

T 类型的对象或引用的列表初始化定义如下:

  • 如果初始值设定项列表没有元素并且 T 是具有默认构造函数的类类型,则该对象将被值初始化。
  • 否则,如果 T 是聚合,则执行聚合初始化 (8.5.1)

到:

T 类型的对象或引用的列表初始化定义如下:

  • 如果 T 是聚合,则执行聚合初始化 (8.5.1)
  • 否则,如果初始化列表没有元素并且 T 是具有默认构造函数的类类型,则该对象将被值初始化。

所以foo{}场景A中仍然是聚合初始化。

  • @JenyaKh 缺陷报告向后应用到相应的标准。如果您愿意的话,它们是补丁更新:) (4认同)
  • @JenyaKh 问题 1301 是针对 C++11 的缺陷,因此符合要求的 C++11 编译器应该实现此更改。 (3认同)