聚合初始化不是值初始化
如果给定的类,比如说S
,是一个聚合,那么
S s{};
是聚合初始化,而不是值初始化,并且将绕过 的任何构造函数S
,即使它们被删除或私有。聚合初始化的结果通常是聚合的 (public (1) ) 数据成员的值初始化。
(1) 如下所示,具有任何私有数据成员的类绝不是聚合类,不通过任何 C++11 到 C++20 标准。
什么是聚合类的定义受以下约束:
其中与聚合的典型混淆是 C++11 到 C++17 对没有任何用户提供的(2)构造函数的较弱要求,这在 C++20 中变得更加严格,要求没有任何用户-声明的构造函数。
(2) 用户提供函数的定义由C++11 中的 [dcl.fct.def.default ]/4和 C++14 中的[dcl.fct.def.default]/5到C++20;在所有这些语言版本中,用户提供的定义基本相同。
C++11、C++14 和 C++17 之间的聚合定义也有其他变化,这些变化并不为人所知,但同样增加了 C++20 之前的聚合混乱;我们将通过几个示例来突出它们。
示例是聚合吗?
对于下面的每个示例;如果S
示例的类是聚合(对于特定语言版本),则以下格式正确:
S s{};
上述所有示例中的聚合规则同样适用于任何类型的构造函数(假设它们在其他方面适用,例如允许显式默认或删除),而不仅仅是S()
.
struct S {};
- C++11:是的
- C++14:是的
- C++17:是的
- C++20:是的
struct S {
int x;
};
- C++11:是的
- C++14:是的
- C++17:是的
- C++20:是的
struct S {
int x{42};
};
- C++11:否(具有默认成员初始化程序)
- C++14:是的
- C++17:是的
- C++20:是的
class S {
int x;
};
- C++11:没有
- C++14:没有
- C++17:没有
- C++20:没有
有一个私有数据成员。
struct S {
S() = default;
};
- C++11:是的
- C++14:是的
- C++17:是的
- C++20:否(具有用户声明的构造函数)
struct S {
private:
S() = default;
};
- C++11:是的
- C++14:是的
- C++17:是的
- C++20:否(具有用户声明的构造函数)
struct S {
S() = delete;
};
- C++11:是的
- C++14:是的
- C++17:是的
- C++20:否(具有用户声明的构造函数)
struct S {
S();
};
S::S() = default;
- C++11:否(具有用户提供的构造函数)
- C++14:没有(...)
- C++17:没有(...)
- C++20:否(具有用户声明的构造函数)
显式默认定义不符合规定,视为用户提供;回顾 [dcl.fct.def.default]/4 (C++11) / [dcl.fct.def.default]/5 (C++14, C++17):
如果函数是用户声明的,并且在其第一次声明时没有显式默认或删除,则该函数是用户提供的。
struct S {
explicit S() = default;
};
- C++11:是的
- C++14:是的
- C++17:否(有
explicit
构造函数)
- C++20:否(具有用户声明的构造函数)
C++17 增加了聚合不能有explicit
构造函数的要求。
struct S {
int x{42};
S() = delete;
};
- C++11:否(具有默认成员初始化程序)
- C++14:是的
- C++17:是的
- C++20:否(具有用户声明的构造函数)
C++14 删除了 C++11 对聚合没有默认成员初始值设定项的要求。
struct S {
int x{42};
explicit S() = delete;
};
- C++11:否(具有默认成员初始化程序)
- C++14:是的
- C++17:否(有
explicit
构造函数)
- C++20:否(具有用户声明的构造函数)