5

我试图理解@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.

以及为什么这段代码无法在 c++11 中编译:

方案 C

struct foo {
  foo() = delete;
  foo(int) {};
};

foo f{}; // error call to deleted constructor

他说重点是第一个 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 默认构造函数,并且代码应该编译失败。

4

1 回答 1

3

由于核心问题 1301是针对 C++11 的缺陷,因此列表初始化的优先级从:

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

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

到:

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

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

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

于 2016-09-20T09:17:38.890 回答