为什么一个结构有另一个结构作为成员包装在一个联合中,如果没有显式默认构造函数则不能编译?

Why does a struct, that has another struct wrapped in a union as a member not compile without an explicit default constructor?

这就是我说的关系:

struct A{
    int i = 1;
};

struct B{
    union{A a;};
};

void main(){
    B b;
};

在这种情况下,我的编译器 (vs2015) 抱怨 B B::B(void) 的默认构造函数被删除,并指出编译器已生成 B::B

../test.cpp(155): error C2280: "B::B(void)" : Es wurde versucht, auf eine gelöschte Funktion zu verweisen
../test.cpp(152): note: Compiler hat hier "B::B" generiert

(抱歉,我无法说服 msvc 跟我说英语)

这两个代码更改中的任何一个都修复了它:

struct A{
    int i; //removed initialzation of member to 1
};

struct B{
    B(){} //adding explicit default constructor
    union{A a;};
};

我知道添加一个什么都不做的默认构造函数并不是一个复杂或烦人的解决方法,但我真的很想知道为什么 C++ 强制我这样做。

这是因为 [class.default.ctor]p2 表示:

A defaulted default constructor for class X is defined as deleted if:

  • (2.1) X is a union that has a variant member with a non-trivial default constructor and no variant member of X has a default member initializer,

.....

我们可以看到为什么 A 没有来自 [class.default.ctor]p3 的普通默认构造函数,它说:

A default constructor is trivial if it is not user-provided and if:
- (3.1) — its class has no virtual functions (10.6.2) and no virtual base classes (10.6.1), and
- (3.2) —no non-static data member of its class has a default member initializer (10.3), and
- (3.3) — all the direct base classes of its class have trivial default constructors, and
- (3.4) — for all the non-static data members of its class that are of class type (or array thereof), each such class has a trivial default constructor.

this live godbolt example可以看出 删除非静态成员初始值设定项使程序结构良好。

struct A{
    int i ; // no NSDMI
};

struct B{
    union{A a;};
};

形成我们今天的措辞的论文是 n2544:1 Unrestricted Unions (Revision 2),它涵盖了这里的理性:

We have also changed the way implicitly declared special member functions of unions are generated in the following way: if a non-trivial special member function is defined for any member of a union, or a member of an anonymous union inside a class, that special member function will be implicitly deleted (8.4 ¶10) for t he union or class. This prevents the compiler from trying to write code that it cannot know how t o write, and forces the programmer to write that code if it’s needed. The fact that the compiler can’t write such a function is no reason not to let the programmer do so.

一个union只有一个活动成员,如果一个或多个成员不能默认构造,编译器应该如何选择默认激活哪一个?