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

时间:2015-11-04 13:18:54

标签: c++ c++11 constructor c++14 default-constructor

当我编译以下代码的#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;
}
  • for #if 0一切都很好,编译成功。
  • for #if 1编译失败,显示错误消息:
      

    错误:选择的构造函数在复制初始化中是显式的

表达式A a = {};有什么区别,具体取决于A是否为aggreagate?

1 个答案:

答案 0 :(得分:9)

TL; DR:Clang和GCC拒绝您的代码是错误的。无论选择的默认构造函数是explicit还是iCWG 1630的分辨率都使默认初始化格式良好。

privateA的代码变体中,i不是聚合,因为它们不能包含私有成员。但是,只要publicAexplicit就是聚合 1 ,并且由于执行了聚合初始化,因此不会调用构造函数(请参阅蓝框),所以你的构造函数{{1}}是无关紧要的。

enter image description here

但是,只要您引入私有成员,就需要根据红色框进行值初始化。因此[dcl.init] /(8.2)适用:

enter image description here

[dcl.init] /(7.1)定义了这种情况的默认初始化:

enter image description here

§13.3.1.3给出了

  

对于[...]默认初始化,候选人   函数是对象类的所有构造函数   初始化。

在任何时候都不考虑原始上下文 - 复制或直接初始化。 (§13.3.1.7也不适用。)事实上,这是有意的;见CWG #1518

  

此问题由issue 1630的解决方案解决:默认初始化现在使用13.3.1.3 [over.match.ctor],现在允许显式构造函数进行默认初始化。 < / p>

Clang和GCC(以及VC ++)尚未实现相应的DR,因此在拒绝C ++ 14模式下的代码时不正确。

1)  您的类具有用户声明的构造函数,但它不是用户提供,即不会阻止您的类成为聚合。回想一下[dcl.init.aggr] / 1中的定义:

  

聚合是一个没有用户提供的数组或类(第9条)   构造函数(12.1),没有私有或受保护的非静态数据成员   (第11条),没有基类(第10条),也没有虚函数   (10.3)。