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

时间:2015-07-07 20:11:42

标签: c++ c++11 aggregate-initialization

以下是 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)。

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

1 个答案:

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