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

时间:2014-10-18 14:27:08

标签: c++ c++11 language-lawyer initializer-list

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

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 个答案:

答案 0 :(得分:7)

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

  

对象或类型T的引用的列表初始化定义为   如下:
- 如果初始化列表没有元素而T是一个类   使用默认构造函数键入,该对象是值初始化的。
-   否则,如果T是聚合,则执行聚合初始化   (8.5.1)。
- 否则,[...]

  

聚合是一个数组或类(第9条),没有用户提供   施工人员(12.1),[...]
  当初始化程序列表初始化聚合时,如8.5.4中所述,初始化程序列表的元素   被视为聚合成员的初始化者,增加下标或成员顺序。

一旦你的类不再是聚合,list-initialization将查找要调用的构造函数,而不是要初始化的成员。

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

答案 1 :(得分:1)

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

例如

S( std::initializer_list<int> );