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

Ori*_*ent 13 c++ constructor default-constructor c++11 c++14

当我编译#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;
}
Run Code Online (Sandbox Code Playgroud)
  • 对于#if 0所有的罚款,编译成功.
  • 对于#if 1编译失败,错误信息:

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

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

Col*_*mbo 9

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


在你的代码中的变化iprivate,A不是汇总,因为这些不能有私有成员.但是,只要i是聚合1,并且由于执行了聚合初始化而没有调用构造函数(参见蓝框),因此构造函数是无关紧要的.publicAexplicit

在此输入图像描述

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

在此输入图像描述

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

在此输入图像描述

并且§13.3.1.3给出

对于默认初始化,候选函数是正在初始化的对象的类的所有构造函数.

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

问题1630的解决方案解决了这个问题:默认初始化现在使用13.3.1.3 [over.match.ctor],现在允许显式构造函数进行默认初始化.

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


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

骨料是没有用户提供的构造的阵列或一个类(第9节)(12.1),无私有或保护非静态数据成员(第11),没有基类(第10节),并且没有虚拟功能(10.3 ).

  • [CWG 1518](http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1518)与此案有关吗? (2认同)