【问题标题】:Why does an explicitly declared constructor prevent member initialisation with a C++ 11 initialisation list?为什么显式声明的构造函数会阻止使用 C++ 11 初始化列表进行成员初始化?
【发布时间】:2014-10-18 14:27:08
【问题描述】:

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

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
}

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

【问题讨论】:

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


    【解决方案1】:

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

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

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

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

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

    【讨论】:

      【解决方案2】:

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

      例如

      S( std::initializer_list<int> );
      

      【讨论】:

      • 你能写下带有初始化列表参数的构造函数的签名吗?我需要告诉 std::initializer_list 模板列表应该包含哪些类型吗?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-07-31
      • 1970-01-01
      • 2016-07-19
      • 2021-12-18
      • 1970-01-01
      • 2011-05-02
      相关资源
      最近更新 更多