c ++ 11聚合初始化之前的值初始化

时间:2016-09-20 07:49:23

标签: c++ c++11 aggregate language-lawyer value-initialization

我试着理解@bolov对Deleted default constructor. Objects can still be created... sometimes [1]

这个问题的第一个接受的答案

似乎我发现了一个错误,所以它弄乱了整个解释。

@bolov解释了为什么这个代码成功在c ++ 11中编译:

情景A

struct foo {
  foo() = delete;
};

// All bellow OK (no errors, no warnings)
foo f = foo{};
foo f = {};
foo f{}; // will use only this from now on.

为什么这段代码在C ++ 11中编译失败:

情景C

struct foo {
  foo() = delete;
  foo(int) {};
};

foo f{}; // error call to deleted constructor

他说重点是第一个foo是聚合,第二个foo不是聚合。

然后他给出了cppreference的摘录:

  

类型T对象的列表初始化的效果是:           ...

     
      
  • 如果T是聚合类型,则执行聚合初始化。这将处理场景A B D E(和C ++ 14中的F)
  •   
  • 否则,T的构造函数分为两个阶段:

         
        
    • 所有采用std :: initializer_list ...

    • 的构造函数   
    • 否则[...] T的所有构造函数都参与重载决策[...]这将照顾C(和C ++ 11中的F)   ...

    •   
  •   

根据您在方案A 中编写 foo f {}; 的摘录,您将获得聚合初始化。这会很棒。但实际上在c ++ 11(#3337草案,最接近标准)中你有不同的初始化顺序

  

对象或类型T的引用的列表初始化定义如下:

     
      
  • 如果初始化列表没有元素且T是具有默认构造函数的类类型,则该对象是值初始化的。
  •   
  • 否则,如果T是聚合,则执行聚合初始化(8.5.1)
  •   

场景A 中的 foo f {}; 应该导致值初始化,也就是说,将调用DELETED默认构造函数并且代码不能成为编译。

1 个答案:

答案 0 :(得分:3)

由于Core Issue 1301是针对C ++ 11的缺陷,列表初始化的优先级从以下变为:

  

对象或类型T的引用的列表初始化定义如下:

     
      
  • 如果初始化列表没有元素且T是具有默认构造函数的类类型,则该对象是值初始化的。
  •   
  • 否则,如果T是聚合,则执行聚合初始化(8.5.1)
  •   

为:

  

对象或类型T的引用的列表初始化定义如下:

     
      
  • 如果T是聚合,则执行聚合初始化(8.5.1)
  •   
  • 否则,如果初始化列表没有元素且T是具有默认构造函数的类类型,则该对象是值初始化的。
  •   

因此,场景A中的foo{}仍然是聚合初始化。