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

3

我想使用初始化列表来初始化一个结构体,就像这样:

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
}

为什么明确定义的默认构造函数会导致错误?我以为初始化列表是为了避免程序员编写冗长的代码,如第二个构造函数。

2个回答

8
聚合初始化 - 如字面意义所示 - 仅适用于聚合体。向类添加非平凡构造函数会使其成为非聚合体。[dcl.init.list]/3:
列表初始化类型为 T 的对象或引用定义如下: - 如果初始化程序列表没有元素并且 T 是带有默认构造函数的类类型,则该对象被值初始化。 - 否则,如果 T 是一个聚合体,则执行聚合初始化(8.5.1)。 - 否则, [...]
并且
聚合是一个数组或一个类(第9条),其中没有用户提供的构造函数(12.1),[...]。当一个聚合体按照8.5.4指定的初始化程序列表进行初始化时,初始化程序列表的元素将以递增的下标或成员顺序作为聚合体成员的初始化程序。
一旦您的类不再是聚合体,列表初始化将寻找要调用的构造函数而不是要初始化的成员。
原因很简单:如果一个类具有非平凡的构造函数,则初始化该类类型的对象的唯一方法是调用其中一个构造函数。在没有相应构造函数的情况下初始化一个类对象将是一种毁灭性的设计失败。

1

通常情况下,是显式定义的构造函数来初始化结构体。因此,当使用初始化列表时,编译器会搜索一个适当的构造函数。如你自己已经指出的,如果声明一个具有两个int类型参数的构造函数,则可以使用初始化列表来初始化结构体的数据成员,因为将调用此构造函数。或者,您可以提供一个具有一个std :: initializer_list类型参数的构造函数。

例如:

S( std::initializer_list<int> );

请你写出带有初始化列表参数的构造函数的声明吗?我需要告诉 std::initializer_list 模板列表应该包含哪些类型吗? - Knitschi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接