【问题标题】:C++14 value-initialization with deleted constructor删除构造函数的 C++14 值初始化
【发布时间】:2014-07-15 22:51:34
【问题描述】:

我有一些误解:

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

struct A
{
  A() = delete;
};

下一条指令格式正确,效果如何?:

A a{};

来自cppreference value initilization

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

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

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

还是聚合初始化? 谢谢!

【问题讨论】:

  • 不,clang-3.5 和 gcc-4.9 用 -std=c++1y 编译它
  • 我会觉得这很令人惊讶。它看起来像一个突破性的变化。它必须是值初始化,如果它格式正确,它将否定一些删除特殊函数的原因。
  • 我正在查看最新的草稿 N3936,但不知道如何编译。但是你是对的,clang 3.4 和 gcc-4.9 都使用-std=c++1y 编译它。 gcc-4.8 没有并抱怨删除的构造函数。
  • 也许通过这个方案,他们想提供一种仅 POD 结构或其他东西的方法。
  • In all cases, if the empty pair of braces {} is used and T is an aggregate type, aggregate-initialization is performed instead of value-initialization. 您的struct A 是一个(空)聚合。

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


【解决方案1】:

您的struct A 是:

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

因此,根据 § 8.5.1/1 提供的定义,它可以作为一个聚合类型

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

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

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

(1) 根据 cmets 中关于为什么删除的构造函数不计为 用户定义 的要求,以下是标准说(草案 N3936,第 8.4.2/5 节,第 198 页):

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

【讨论】:

  • "(允许显式默认或删除的构造函数)".. 谁说的?答案就在这里,所以请引用规范。
  • 请注意,“它是一个聚合”列表中的最后一个要点不适用于 C++1y。
【解决方案2】:

它的格式很好。 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]中:

一个函数是用户提供的,如果它是用户声明的而不是明确的 在第一次声明时默认或删除。

【讨论】:

  • +1 是 user provided 子句让我失望了。我假设明确默认/删除的构造函数被视为用户提供。
  • “A 是一个聚合”。具体如何?你的报价应该首先证明这一点。
  • +1 for "如果一个函数是用户声明的并且没有显式默认或在第一次声明时被删除,则该函数是用户提供的。" .... deleted 部分让我吃惊!
  • @Nawaz 我总是要查找这个“用户提供”的业务。希望从现在起我会记住它。但这对some compilers seem to get this wrong没有帮助。
  • @Yakk 是的,我倾向于认为这是一个缺陷。删除构造函数应该是提供一个私有的、空的构造函数的干净版本......
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-06-30
  • 2021-06-30
  • 1970-01-01
  • 1970-01-01
  • 2018-11-09
  • 2011-01-25
相关资源
最近更新 更多