使用已删除的构造函数进行C ++ 14值初始化

时间:2014-05-27 06:24:43

标签: c++ language-lawyer c++14

我有一些误解:

让结构A的默认构造函数标记为已删除:

struct A
{
  A() = delete;
};

下一条指令格式正确,有什么影响?:

A a{};

来自cppreference value initilization

  

1)如果T是没有默认构造函数或带有的类类型   用户提供的默认构造函数或删除的默认值   构造函数,该对象是默认初始化的。

但是默认初始化的效果是:

  

如果T是类类型,则调用默认构造函数来提供   新对象的初始值。

或者它的聚合初始化? 谢谢!

2 个答案:

答案 0 :(得分:30)

您的struct A是:

  • 具有以下类别的类类型:
    • 没有用户提供的构造函数 1
    • 没有私有或受保护的非静态数据成员,
    • 没有基类,
    • 没有虚拟成员功能。

因此,根据第8.5.1 / 1节提供的定义,它符合聚合类型

然后是聚合初始化优先于值初始化的优先级。标准说聚合初始化优先于价值初始化(草案N3936,第8.5.4 / 3节,第201页)(强调我的)

  

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

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

(1) 根据评论中关于为什么删除的构造函数不算作用户定义的请求,这是标准说(草案N3936,第8.4.2 / 5节,第198页):

  

如果函数是用户声明的,并且在第一次声明时未明确默认或删除,则该函数是用户提供的。

答案 1 :(得分:20)

结构良好。 A是一个聚合 1 ,根据draft N3936直接列表初始化中使用的空初始值设定项列表导致聚合初始化:

来自§8.5.4/ 3列表初始化[dcl.init.list]

  

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

     

- 如果T是聚合,则执行聚合初始化(8.5.1)。

     

[例如:

     

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

     

....

     

S2 s23{}; // OK: default to 0,0,0

     

...

     

- 结束示例]

     

...

C ++ 11和C ++ 1y之间的相关变化是聚合情况下聚合与值初始化优先级的变化:

C ++ 11带领

  

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

     

- 如果初始化列表没有元素而T是一个类   使用默认构造函数键入,该对象是值初始化的。

     

- 否则,如果T是聚合,则执行聚合初始化(8.5.1)....

接着是上面的例子。

C ++ 1y优先考虑聚合初始化:

  

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

     

- 如果T是聚合,则执行聚合初始化(8.5.1)。

     

...

     

- 否则,如果初始化列表没有元素且T是具有默认构造函数的类类型,则该对象是值初始化的。


1 为什么A是聚合的?

它是C ++ 11和C ++ 14中的聚合。

C ++ 1Y:

  

8.5.1聚合[dcl.init.aggr]

     

聚合是一个数组或类(第9条),没有用户提供的构造函数(12.1),没有私有或受保护的非静态数据成员(第11条),没有基类(第10条),没有虚拟功能(10.3)。

唯一不明显的部分是默认构造函数是否是用户提供的。它不是:

§8.4.2[dcl.fct.def.default]

  

如果函数是用户声明的而非显式的,则用户提供该函数   在第一份声明中默认或删除。