Why does a struct, that has another struct wrapped

2019-07-04 07:04发布

问题:

This is the relationship I am talking about:

struct A{
    int i = 1;
};

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

void main(){
    B b;
};

In this constellation, my compiler (vs2015) complains about the default constructor of B B::B(void) beeing deleted, with the note that the compiler has generated 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

(sorry, I could not convince msvc to talk english to me)

Either of these two code changes fixes it:

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

or

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

I know that adding a default constructor that does nothing is not exactly a complicated or annoying workaround, but I really want to know why C++ forces me to do this.

回答1:

This is because of [class.default.ctor]p2 which says:

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,

.....

and we can see why A does not have a trivial default constructor from [class.default.ctor]p3 which says:

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.

We can see from this live godbolt example that removing the non-static member initializer makes the program well formed.

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

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

The paper that resulted in the wording we have today is n2544:1 Unrestricted Unions (Revision 2), it covers the rational here:

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.

A union has only one active member, if one or more of the members can not be default constructed how should the compiler choose which one to make active by default?