在聚合初始化之前的c++11值初始化

c++11 value-initialization prior to aggregate-initialization

本文关键字:初始化 c++11      更新时间:2023-10-16

我试图理解@bolov对删除默认构造函数问题的第一个接受的答案。对象仍然可以被创建…有时[1]

好像我在那里发现了一个错误,所以它把整个解释搞砸了。

@bolov解释了为什么这段代码可以在c++11中成功编译:

场景

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类型对象的list初始化效果如下:…

  • 如果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)

因此foo f {};场景A应该导致值初始化,即调用DELETED默认构造函数,代码编译失败。

作为Core Issue 1301的结果,这是c++ 11的一个缺陷,列表初始化的优先级从:

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

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

:

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

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

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