首页 文章

空括号调用默认构造函数或构造函数采用std :: initializer_list吗?

提问于
浏览
8

以下是 Effective Modern C++ (第55页)的引用:

“假设你使用一组空括号来构造一个支持默认构造函数的对象,并且还支持std :: initializer_list构造 . 你的空括号是什么意思?等等 . 规则是你得到默认构造 . ”

我用std :: array尝试过这个:

std::array<int, 10> arr{};

并得到g的警告(版本4.8.2):

警告:缺少成员'std :: array <int,10ul> :: _ M_elems'的初始值设定项

这是在尝试从空 std::initializer_list 构造 std::array 时获得的警告(有关此警告的讨论,请参阅Why can I initialize a regular array from {}, but not a std::array) .

那么,为什么上面的代码行不能解释为调用默认构造函数?

1 回答

  • 8

    那是因为std::array是一个聚合,因此aggregate initialization被执行,这包含在draft C++11 standard部分 8.5.4 [dcl.init.list]中,其中说:

    对象或类型T的引用的列表初始化定义如下:如果初始化列表没有元素且T是具有默认构造函数的类类型,则对象是值初始化的 . 否则,如果T是聚合,则执行聚合初始化(8.5.1) . double ad [] = {1,2.0}; // 好
    int ai [] = {1,2.0}; //错误:缩小

    struct S2 {
    int m1;
    双m2,m3;
    };

    S2 s21 = {1,2,3.0}; // 好
    S2 s22 {1.0,2,3}; //错误:缩小
    S2 s23 {}; // OK:默认为0,0,0

    我们可以看到它是不是聚合,然后列表继续说:

    否则,如果T是std :: initializer_list的特化,则如下所述构造initializer_list对象,并用于根据相同类型的类(8.5)中的对象初始化规则初始化对象 . 否则,如果T是类类型,则考虑构造函数 . 枚举适用的构造函数,并通过重载决策(13.3,13.3.1.7)选择最佳构造函数 . 如果转换任何参数需要缩小转换(见下文),则程序格式错误 .

    我们可以确认 std::array23.3.2.1 [array.overview]部分的聚合:

    数组是一个聚合(8.5.1),可以使用语法数组<T,N> a = 初始化;
    其中initializer-list是一个逗号分隔的列表,最多包含N个元素,其类型可转换为T.

    引用的 8.5.1 部分是 8.5.1 聚合[dcl.init.aggr]并说:

    当初始化程序列表初始化聚合时,如8.5.4中所述,初始化程序列表的元素被视为聚合成员的初始化程序,增加下标或成员顺序[...]

    然后我们回到 8.5.4 这个我们开始的地方 .

相关问题