【问题标题】:Explicit defaulted default constructor and aggregates显式默认的默认构造函数和聚合
【发布时间】:2016-02-05 00:20:31
【问题描述】:

当我编译以下代码的#if 0#if 1 版本时,如何解释差异:

#include <cstdlib>

struct A
{ 
    explicit A() = default; // explicitly defaulted or deleted constructors are allowed for aggregates (since C++11)
#if 1
private :
#endif
    int i;
};

int
main()
{
    A a = {};
    return EXIT_SUCCESS;
}
  • #if 0 一切正常,编译成功。
  • 对于#if 1 编译失败并出现错误消息:

    错误:选择的构造函数在复制初始化中是显式的

根据A 是否聚合,表达式A a = {}; 有什么区别?

【问题讨论】:

  • 我想你自己回答了。当您收到错误 A 不是聚合结构时。所以你不能使用初始化列表来初始化它。
  • @Jonathan 我自己的理解(愚蠢的“它取决于聚合性”)不太清楚。我想听听确切的解释。

标签: c++ c++11 constructor c++14 default-constructor


【解决方案1】:

TL;DR:Clang 和 GCC 拒绝您的代码是错误的。 CWG 1630 的决议使默认初始化格式良好,无论选择的默认构造函数是否为 explicit


iprivate 的代码变体中,A 不是聚合,因为它们不能有私有成员。但是,只要ipublicA 就是一个聚合1,并且由于执行了聚合初始化(见蓝色框),所以没有调用构造函数,所以你的构造函数是 @987654338 @ 无关紧要。

但是,一旦您引入私有成员,您就需要按照红框进行值初始化。因此 [dcl.init]/(8.2) 适用:

[dcl.init]/(7.1) 为这种情况定义了默认初始化:

§13.3.1.3 给出了

对于 […] 默认初始化,候选 函数是对象的类的所有构造函数 初始化。

在任何时候都不会考虑原始上下文 - 复制或直接初始化。 (§13.3.1.7 也不适用。)事实上,这是有意的;见CWG #1518:

issue 1630 的决议解决了这个问题:默认初始化现在使用 13.3.1.3 [over.match.ctor],它现在允许使用显式构造函数进行默认初始化。

Clang 和 GCC(和 VC++)还没有实现相应的 DR,因此拒绝 C++14 模式下的代码是不正确的。


1) 您的类有一个用户声明的构造函数,但它不是用户提供,即不妨碍您的类成为一个聚合。回忆一下 [dcl.init.aggr]/1 中的定义:

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

【讨论】:

  • CWG 1518与本案无关吗?
  • @bogdan 等等,我最初的结论正确吗?
  • 我会这么说,但我自己也不是 100% 确定 :-)。
  • @bogdan 无论如何,非常感谢这位博士。我完全错过了查找这些。现在将调整我的答案。
  • @bogdan 那么“本节”究竟是什么意思呢? 13.3.1 如何比 13.3.1.7 更像一个“部分”?还是只有我,在上下文中是明确的?
猜你喜欢
  • 1970-01-01
  • 2016-07-23
  • 1970-01-01
  • 2011-02-19
  • 2012-06-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-06-24
相关资源
最近更新 更多