为什么const成员结构中需要构造函数?

Chr*_*ger 35 c++ c++11

我有一个类似于这样的代码:

class AClass {
public:
  struct AStruct { };

  AClass(){}

private:
  const AStruct m_struct;
};

int main() {
  AClass a;
}
Run Code Online (Sandbox Code Playgroud)

它抛出此编译错误(使用Clang LLVM版本5.1):

error: constructor for 'AClass' must explicitly initialize 
       the const member 'm_struct'
Run Code Online (Sandbox Code Playgroud)

如果我指定一个C++ 11默认构造函数struct AStruct,我会得到同样的错误:

  struct AStruct {
    AStruct() = default;
  };
Run Code Online (Sandbox Code Playgroud)

但是,这可以通过编写一个空体的构造函数来解决:

  struct AStruct {
    AStruct(){}  // fixed
  };
Run Code Online (Sandbox Code Playgroud)

为什么我需要指定一个空构造函数?它是不是通过结构的公共访问自动创建的?

为什么C++ 11默认构造函数不解决问题?

chr*_*ris 27

来自§8.5[dcl.init]/7:

如果程序要求对const限定类型T的对象进行默认初始化,则T应为具有用户提供的默认构造函数的类类型.

default的默认构造函数AClass初始化const成员(参见下文),以便该成员必须具有用户提供的默认构造函数.使用= default不会导致用户提供的默认构造函数,如§8.4.2[dcl.fct.def.default]/4中所示:

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


根据§12.6.2[class.base.init]/8默认初始化该成员:

在非委托构造函数中,如果给定的非静态数据成员或基类未由mem-initializer-id指定(包括没有mem-initializer-list的情况,因为构造函数没有ctor-initializer)然后,实体不是抽象类(10.4)的虚基类

- 如果实体是具有大括号或等于初始化程序的非静态数据成员,则按照8.5中的规定初始化该实体;
- 否则,如果实体是匿名联合或变体成员(9.5),则不执行初始化;
- 否则,实体默认初始化(8.5).

  • [更糟](http://coliru.stacked-crooked.com/a/1b7b4fd8fefc3fa5)这段代码实际上做了一些事情(并且很有用),但是我们得到了一个编译器错误.@PengZhang G ++ 4.8在这里违反了标准,而不是铿锵. (3认同)
  • @Casey [错误的问题编号](http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#253). (3认同)

Yak*_*ont 17

从@ chris的答案中被盗我们有这一段:§8.5[dcl.init]/7:

如果程序要求对const限定类型T的对象进行默认初始化,则T应为具有用户提供的默认构造函数的类类型.

然后我们可以构建一个完全荒谬的案例来说明这个限制:

struct Foo {};
int main() {
  const Foo f;
}
Run Code Online (Sandbox Code Playgroud)

根据标准的规定,它无法在clang中编译.您的代码就是这样,但作为另一个类/结构的成员变量.

我们甚至可以这样做:

struct Foo {int x = 3;};
int main() {
  const Foo f;
}
Run Code Online (Sandbox Code Playgroud)

所有数据显然都已初始化.最后一个例子让我相信这是标准中的缺陷.

这个想法可能与未初始化的POD类型有关const,但是措辞阻止了与之无关的代码.现代C++中的默认构造函数通常都足够好,并且强制Foo(){}形式很差.