以下是 Effective Modern C ++ (第55页)的引用:
“假设你使用一组空括号来构造一个支持默认构造函数的对象,并且还支持std :: initializer_list构造。你的空括号是什么意思?等等规则是你得到默认构造。”< / p>
我用std :: array:
尝试了这个std::array<int, 10> arr{};
并收到g ++(版本4.8.2)的警告:
警告:缺少成员'std :: array&lt; int,10ul&gt; :: _ M_elems'
的初始值设定项
这是尝试从空std::array
构建std::initializer_list
时获得的警告(有关此警告的讨论,请参阅Why can I initialize a regular array from {}, but not a std::array)。
那么,为什么上面的代码行不能解释为调用默认构造函数?
答案 0 :(得分:8)
这是因为std::array是一个聚合,因此aggregate initialization已执行,draft C++11 standard部分8.5.4
[dcl.init.list] < / em>其中说:
对象或类型T的引用的列表初始化定义如下:
如果初始化列表没有元素且T是具有默认构造函数的类类型,则对象为 值初始化。
否则,如果T是聚合,则执行聚合初始化(8.5.1)。
double ad[] = { 1, 2.0 }; // OK int ai[] = { 1, 2.0 }; // error: narrowing struct S2 { int m1; double m2, m3; }; S2 s21 = { 1, 2, 3.0 }; // OK S2 s22 { 1.0, 2, 3 }; // error: narrowing S2 s23 { }; // OK: default to 0,0,0
我们可以看到它是不是聚合,然后列表继续说:
- 否则,如果T是std :: initializer_list的特化,则是initializer_list对象 如下所述构造并用于根据初始化规则初始化对象 来自相同类型的对象(8.5)。
- 否则,如果T是类类型,则考虑构造函数。列举了适用的构造函数 通过重载决策选择最好的一个(13.3,13.3.1.7)。如果缩小转换(见 如果需要转换任何参数,程序就是格式错误。
我们可以确认std::array
是来自23.3.2.1
[array.overview] 的汇总:
数组是一个聚合(8.5.1),可以用它初始化 语法
array<T, N> a = { initializer-list };
其中initializer-list是最多包含N个元素的逗号分隔列表 其类型可转换为T.
引用的8.5.1
部分是8.5.1
聚合 [dcl.init.aggr] 并说:
按指定的初始化列表初始化聚合时 在8.5.4中,初始化列表的元素被视为 增加下标的聚合成员的初始化程序 或会员订单[...]
然后我们全面回到我们开始的地方8.5.4
。