聚合初始化与统一初始化

Adr*_*ian 5 c++

我对 C++11 统一初始化了解得越多,我就越困惑。在 Effective Modern C++(第 55 页)中的 Scott Meyers 说,声明

Widget w2{};
Run Code Online (Sandbox Code Playgroud)

始终调用默认构造函数(即使存在带有std::initializer_list参数的构造函数)。

乍一看,这似乎与 Stroustrup 书“C++ 编程语言”的第 4 版一致,例如根据第 1200 页上的表格声明

std::atomic<T> x;
Run Code Online (Sandbox Code Playgroud)

使原子变量未初始化,而

std::atomic<T> x {};
Run Code Online (Sandbox Code Playgroud)

调用“默认构造函数”,以便 x 表示一个值初始化的 T 对象。

但是,我无法相信std::atomic<T> x;不再调用 C++11 中的默认构造函数,所以我在这里完全感到困惑。

最后,在查看了 C++11 标准(n3337 草案)后,我的困惑更大了。在第 1102 页,我们有:

template <> struct atomic<integral > {
  //[...] list of non-constructor functions
  atomic() noexcept = default;
  constexpr atomic(integral ) noexcept;
  atomic(const atomic&) = delete;
  //[...] other non-constructor functions
};
Run Code Online (Sandbox Code Playgroud)

在第 1104 页(第 29.5.5 点)我们看到

原子积分特化和特化原子应有标准布局。它们每个都有一个普通的默认构造函数和一个普通的析构函数。它们都应支持聚合初始化语法。

那么具有用户定义构造函数的类现在支持聚合初始化吗?这是因为构造函数是constexpr

当我们写作时会发生什么

std::atomic<T> x {};
Run Code Online (Sandbox Code Playgroud)

这是聚合初始化吗?或者调用(平凡的)默认构造函数?

eer*_*ika 5

那么具有用户定义构造函数的类现在支持聚合初始化吗?

仅聚合支持聚合初始化。仅当构造函数定义为默认或删除时,聚合才能具有用户定义的构造函数。

这将在 C++20 中发生变化,其中根本不允许用户声明构造函数。

这是因为构造函数是 consexpr 吗?

constexpr对此没有影响。

std::atomic<T> x {};
Run Code Online (Sandbox Code Playgroud)

这是聚合初始化吗?

这是列表初始化。如果类型是聚合,则列表初始化将聚合初始化对象。std::atomic不是聚合,因为它有一个用户提供的构造函数,既不默认也不删除:

constexpr atomic( T desired ) noexcept; // (2) (since C++11)
Run Code Online (Sandbox Code Playgroud)

对于std::atomic,适用此列表初始化规则:

  • 否则,如果初始值设定项列表没有元素并且 T 是具有默认构造函数的类类型,则该对象是值初始化的

并且值初始化会调用此类的默认构造函数。