为什么显式声明的构造函数会使用C++11初始化列表阻止成员初始化

Why does an explicitly declared constructor prevent member initialisation with a C++ 11 initialisation list?

本文关键字:初始化 C++11 列表 成员 声明 构造函数 为什么      更新时间:2023-10-16

我想用这样的初始化列表初始化一个结构:

struct S
{
    int a;
    int b;
    // S() : a(0), b(0){}  // uncommenting will cause compile error: 
                           // error C2440: 'initializing' : cannot convert from 'initializer-list' to 'S'
    // S(int aArg, int bArg) : a(aArg), b(bArg) {}    // adding this removes the error
}
int main()
{
    S s{1,2};   // initialise with list
}

为什么显式声明的默认构造函数会导致错误,有充分的理由吗?我认为引入初始化列表是为了避免程序员编写像第二个构造函数那样乏味的代码。

顾名思义,聚合初始化仅适用于聚合。向类中添加一个非平凡的构造函数使其成为非聚合。[dcl.init.list]/3:

类型T的对象或引用的列表初始化定义为如下:
-如果初始值设定项列表没有元素,并且T是一个类类型,则对象被值初始化
--否则,如果T是聚合,则执行聚合初始化(8.5.1).
--否则,[…]

聚合是一个数组或类(第9条),其中没有提供用户构造函数(12.1),[…]
当聚合由初始化器列表初始化时,如8.5.4所述,初始化器列表的元素以递增下标或成员顺序作为聚合成员的初始值设定项。

一旦您的类不再是聚合,列表初始化将查找要调用的构造函数,而不是要初始化的成员。

原因很简单:如果一个类有非平凡的构造函数,有效初始化该类类型的对象的唯一方法是调用该对象的构造函数之一。在没有相应构造函数的情况下初始化类对象将是一个毁灭性的设计失败。

应该是显式定义的构造函数来初始化结构。因此,当使用初始值设定项列表时,编译器会搜索适当的构造函数。正如您自己已经指出的那样,如果用两个int类型的参数声明一个构造函数,那么您可以使用初始值设定项列表来初始化结构的数据成员,因为这个构造函数将被调用。或者,您可以提供一个构造函数,该构造函数有一个std::initializer_list类型的参数。

例如

S( std::initializer_list<int> );