显式默认默认构造函数和聚合
Explicit defaulted default constructor and aggregates
如何解释差异,当我编译以下代码的 #if 0
和 #if 1
版本时:
#include <cstdlib>
struct A
{
explicit A() = default; // explicitly defaulted or deleted constructors are allowed for aggregates (since C++11)
#if 1
private :
#endif
int i;
};
int
main()
{
A a = {};
return EXIT_SUCCESS;
}
- 对于
#if 0
一切正常,编译成功
- for
#if 1
编译失败并显示错误消息:
error: chosen constructor is explicit in copy-initialization
根据 A
是否聚合,表达式 A a = {};
有何不同?
TL;DR:Clang 和 GCC 拒绝您的代码是错误的。 CWG 1630 的决议使默认初始化格式正确,无论选择的默认构造函数是否 explicit
。
在 i
是 private
的代码变体中,A
不是聚合,因为它们不能有私有成员。但是,只要 i
是 public
,A
就是聚合 1,并且因为执行了聚合初始化,所以没有调用构造函数(见蓝色框),所以你的构造函数是 explicit
是无关紧要的。
但是,一旦引入私有成员,就需要按照红框进行值初始化。因此 [dcl.init]/(8.2) 适用:
[dcl.init]/(7.1) 为这种情况定义默认初始化:
而 §13.3.1.3 给出
For […] default-initialization, the candidate
functions are all the constructors of the class of the object being
initialized.
在任何时候都不会考虑原始上下文——复制或直接初始化。 (§13.3.1.7 也不适用。)事实上,这是有意的;见 CWG #1518:
This issue is resolved by the resolution of issue 1630: default initialization now uses 13.3.1.3 [over.match.ctor], which now permits explicit constructors for default-initialization.
Clang 和 GCC(以及 VC++)尚未实现相应的 DR,因此在 C++14 模式下拒绝代码是不正确的。
1)
您的 class 有一个用户声明的构造函数,但它不是用户 提供的 ,即不妨碍您的 class 成为聚合。回想一下 [dcl.init.aggr]/1:
中的定义
An aggregate is an array or a class (Clause 9) with no user-provided
constructors (12.1), no private or protected non-static data members
(Clause 11), no base classes (Clause 10), and no virtual functions
(10.3).
如何解释差异,当我编译以下代码的 #if 0
和 #if 1
版本时:
#include <cstdlib>
struct A
{
explicit A() = default; // explicitly defaulted or deleted constructors are allowed for aggregates (since C++11)
#if 1
private :
#endif
int i;
};
int
main()
{
A a = {};
return EXIT_SUCCESS;
}
- 对于
#if 0
一切正常,编译成功 - for
#if 1
编译失败并显示错误消息:error: chosen constructor is explicit in copy-initialization
根据 A
是否聚合,表达式 A a = {};
有何不同?
TL;DR:Clang 和 GCC 拒绝您的代码是错误的。 CWG 1630 的决议使默认初始化格式正确,无论选择的默认构造函数是否 explicit
。
在 i
是 private
的代码变体中,A
不是聚合,因为它们不能有私有成员。但是,只要 i
是 public
,A
就是聚合 1,并且因为执行了聚合初始化,所以没有调用构造函数(见蓝色框),所以你的构造函数是 explicit
是无关紧要的。
但是,一旦引入私有成员,就需要按照红框进行值初始化。因此 [dcl.init]/(8.2) 适用:
[dcl.init]/(7.1) 为这种情况定义默认初始化:
而 §13.3.1.3 给出
For […] default-initialization, the candidate functions are all the constructors of the class of the object being initialized.
在任何时候都不会考虑原始上下文——复制或直接初始化。 (§13.3.1.7 也不适用。)事实上,这是有意的;见 CWG #1518:
This issue is resolved by the resolution of issue 1630: default initialization now uses 13.3.1.3 [over.match.ctor], which now permits explicit constructors for default-initialization.
Clang 和 GCC(以及 VC++)尚未实现相应的 DR,因此在 C++14 模式下拒绝代码是不正确的。
1) 您的 class 有一个用户声明的构造函数,但它不是用户 提供的 ,即不妨碍您的 class 成为聚合。回想一下 [dcl.init.aggr]/1:
中的定义An aggregate is an array or a class (Clause 9) with no user-provided constructors (12.1), no private or protected non-static data members (Clause 11), no base classes (Clause 10), and no virtual functions (10.3).