C++ 默认构造函数与具有非平凡默认构造函数的变体成员联合

C++ Default constructors in union with variant member with non-trivial default constructor

我最近阅读了联合默认构造函数的描述: Default Constructor

有如下规则:

Blockquote Deleted implicitly-declared default constructor: [...] T is a union with at least one variant member with non-trivial default constructor, and no variant member of T has a default member initializer.[...]

然后我决定做个练习,验证规则。

struct Member {
 public:
  // Member() : mX(0) {}
  virtual int GetX() {
    return mX;
  }
  int mX;
};

union DefaultConstructor {
  int mA;
  Member mMember;
  int GetA();
};

使用 gcc v5.3.1(我知道它很旧)我收到预期的错误:

> ../src/DefaultConstrcutors.cpp: In function ‘void
> Test_DefaultConstructors()’: ../src/DefaultConstrcutors.cpp:26:22:
> error: use of deleted function
> ‘DefaultConstructor::DefaultConstructor()’    DefaultConstructor foo;
>                       ^ In file included from ../src/DefaultConstrcutors.cpp:19:0:
> ../src/DefaultConstructors.h:155:7: note:
> ‘DefaultConstructor::DefaultConstructor()’ is implicitly deleted
> because the default definition would be ill-formed:  union
> DefaultConstructor {
>        ^ ../src/DefaultConstructors.h:157:10: error: union member ‘DefaultConstructor::mMember’ with non-trivial ‘Member::Member()’   
> Member mMember;
>           ^

好的,所以根据规则,如果我为变体成员提供默认成员初始值设定项,那么它应该可以编译。所以我将联合定义更改为:

union DefaultConstructor {
      int mA = 0;
      Member mMember;
      int GetA();
    };

现在应该可以编译了,但我收到了同样的错误。

下一步是为 mMember 而不是 mA 提供默认初始化程序(只有一个联合变体成员可能具有默认初始化程序)。

union DefaultConstructor {
      int mA;
      Member mMember{};
      int GetA();
    };

现在可以编译了。

问题是:当 mA 具有默认初始化程序时,为什么在第二种情况下它没有编译?根据提到的规则,它应该是可能的。这里提供了更多类似的规则:Union declaration

If a union contains a non-static data member with a non-trivial default constructor, the default constructor of the union is deleted by default unless a variant member of the union has a default member initializer .

有人知道为什么它不起作用吗?

您好, 彼得

cppreference 通常是一个不错的信息源,但这里的编译器是正确的。 C++11 的草案 n3337 在 9.5 联合 [class.union] 中包含一个非规范但明确的说明:

If any non-static data member of a union has a non-trivial default constructor (12.1), copy constructor (12.8), move constructor (12.8), copy assignment operator (12.8), move assignment operator (12.8), or destructor (12.4), the corresponding member function of the union must be user-provided or it will be implicitly deleted (8.4.3) for the union.

没有提到一个成员有一个默认的成员初始值设定项。

C++14 的 n4296 草案中仍然存在相同的说明,因此我认为它在实际的 C++ 标准中应该仍然相同。注释当然是非规范性的,但其目的是为了更清楚地解释标准,所以我认为 cppreference 的解释是错误的,因为它不尊重那个注释,而 gcc 解释是正确的。