为什么在已删除的默认 ctor 旁边定义一个空的复制 ctor 会使空列表的值初始化失败?
Why does defining an empty copy ctor beside a deleted default ctor make a value initialization with empty list fail?
简而言之,为什么下面的代码表现得像评论中描述的那样?
struct A
{
A() = delete;
//A(const A&) {} // uncommenting this...
};
int main()
{
A a{}; // ... breaks this
//A(); // this fails in either case because of `A() = delete;` only
}
我应该查看标准的哪一部分(或至少 cppreference 上的一页)才能理解这一点?
但是,写 A(const A&) = default;
而不是 //A(const A&) {}
不会 破坏 A a{};
。那这个呢?我认为根本原因是一样的,但是真正了解C++的人的一句话比我认为。
更好
没有 user-provided copy constructor, A
is an aggregate. Yes, even though we deleted the default constructor. It's something that was .
所以,在 C++20 之前,A a{};
是 aggregate initialization, and so doesn't use the deleted constructor. When you uncomment the copy constructor, A
stops being an aggregate, thus turning the aggregate initialization into value initialization。因此 a
的初始化将尝试调用已删除的构造函数。
为了从标准中推断初始化器的含义,通常从 [dcl.init]/16 开始。通过项目符号,可以发现初始化程序的属性(当与相关类型的属性匹配时)将如何影响初始化发生的方式。
聚合初始化不是值初始化
如果给定的 class,比如说 S
,是一个聚合,那么
S s{};
是聚合初始化,不是值初始化,并且会绕过S
的任何构造函数,即使它们被删除或私有。聚合初始化的结果通常是聚合的(public(1))数据成员的值初始化。
(1) 如下所示,具有任何私有数据成员的 class 永远不是聚合 class,不是通过任何 C++11 到 C+ +20 个标准。
什么是聚合 class 的定义受制于:
- [dcl.init.aggr]/1 in C++11 (N3337)
- [dcl.init.aggr]/1 in C++14 (N4140)
- [dcl.init.aggr]/1 in C++17 (N4659)
- [dcl.init.aggr]/1 in C++20 (N4861)
与聚合的典型混淆是 C++11 到 C++17 的较弱要求,即没有任何 用户提供的(2) 构造函数,在 C++20 中变得更加严格,要求没有任何 用户声明的 构造函数。
(2) 在 C++14 到 C++20 中,什么算作用户提供的函数的定义由 [dcl.fct.def.default]/4 in C++11 and [dcl.fct.def.default]/5 管理; user-provided 的定义在所有这些语言版本中基本相同。
C++11、C++14 和 C++17 之间的聚合定义也有其他更改,这些更改并不为人所知,但同样增加了 C+ 之前的聚合混淆+20;我们将通过几个示例来突出显示它们。
这个例子是合计吗?
对于下面的每个例子;如果示例的 class 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):
A function is user-provided if it is user-declared and not explicitly defaulted or deleted on its first declaration.
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:无(有用户声明的构造函数)
简而言之,为什么下面的代码表现得像评论中描述的那样?
struct A
{
A() = delete;
//A(const A&) {} // uncommenting this...
};
int main()
{
A a{}; // ... breaks this
//A(); // this fails in either case because of `A() = delete;` only
}
我应该查看标准的哪一部分(或至少 cppreference 上的一页)才能理解这一点?
但是,写 A(const A&) = default;
而不是 //A(const A&) {}
不会 破坏 A a{};
。那这个呢?我认为根本原因是一样的,但是真正了解C++的人的一句话比我认为。
没有 user-provided copy constructor, A
is an aggregate. Yes, even though we deleted the default constructor. It's something that was
所以,在 C++20 之前,A a{};
是 aggregate initialization, and so doesn't use the deleted constructor. When you uncomment the copy constructor, A
stops being an aggregate, thus turning the aggregate initialization into value initialization。因此 a
的初始化将尝试调用已删除的构造函数。
为了从标准中推断初始化器的含义,通常从 [dcl.init]/16 开始。通过项目符号,可以发现初始化程序的属性(当与相关类型的属性匹配时)将如何影响初始化发生的方式。
聚合初始化不是值初始化
如果给定的 class,比如说 S
,是一个聚合,那么
S s{};
是聚合初始化,不是值初始化,并且会绕过S
的任何构造函数,即使它们被删除或私有。聚合初始化的结果通常是聚合的(public(1))数据成员的值初始化。
(1) 如下所示,具有任何私有数据成员的 class 永远不是聚合 class,不是通过任何 C++11 到 C+ +20 个标准。
什么是聚合 class 的定义受制于:
- [dcl.init.aggr]/1 in C++11 (N3337)
- [dcl.init.aggr]/1 in C++14 (N4140)
- [dcl.init.aggr]/1 in C++17 (N4659)
- [dcl.init.aggr]/1 in C++20 (N4861)
与聚合的典型混淆是 C++11 到 C++17 的较弱要求,即没有任何 用户提供的(2) 构造函数,在 C++20 中变得更加严格,要求没有任何 用户声明的 构造函数。
(2) 在 C++14 到 C++20 中,什么算作用户提供的函数的定义由 [dcl.fct.def.default]/4 in C++11 and [dcl.fct.def.default]/5 管理; user-provided 的定义在所有这些语言版本中基本相同。
C++11、C++14 和 C++17 之间的聚合定义也有其他更改,这些更改并不为人所知,但同样增加了 C+ 之前的聚合混淆+20;我们将通过几个示例来突出显示它们。
这个例子是合计吗?
对于下面的每个例子;如果示例的 class 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):
A function is user-provided if it is user-declared and not explicitly defaulted or deleted on its first declaration.
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:无(有用户声明的构造函数)