显式默认默认构造函数和聚合

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;
}

根据 A 是否聚合,表达式 A a = {}; 有何不同?

TL;DR:Clang 和 GCC 拒绝您的代码是错误的。 CWG 1630 的决议使默认初始化格式正确,无论选择的默认构造函数是否 explicit


iprivate 的代码变体中,A 不是聚合,因为它们不能有私有成员。但是,只要 ipublicA 就是聚合 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).