My story starts off the same as this person's here:
Unions in C++11: default constructor seems to be deleted
The resolution here (now about three years old) is a bit unsatisfactory, because the "Digging into the standard" that the author did ended up with concluding that the behavior was as described in the standard, but unfortunately the quote is from a Note, and those are supposed to be non-normative (I've been told). Anyways, there's a link to an old bug report on gcc that is claimed to be fixed, and they also claim that the code compiles in clang, however I'm having issues (with the same and similar code). The matter boils down to a whether or not a union-like class with a default initialized variant member should compile whether or not there is another variant member (in the same variant set) that has a non-trivial constructor.
struct X {
X() {} //non-trivial default constructor
};
struct U {
union {
X x;
int i{0}; //default member initializer
};
};
U u; //error: default constructor deleted
These failed with -std=c++14
and -std=c++17
on gcc version 7.3.0 (Ubuntu 7.3.0-27ubuntu1~18.04)
as well as clang version 6.0.0-1ubuntu2
.
There seems to be a history of change in the standard, and so I'll put forth what I've found:
N3690/N4140:
[12.1.4/Constructors] ...A defaulted default constructor for class X is defined as deleted if:
- X is a union-like class that has a variant member with a non-trivial default constructor
[9.5.2/Unions]... [Note: 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. — end note]
N4659/N4727:
[15.1.5/Constructors] ...A defaulted default constructor for class X is defined as deleted if:
- 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
[12.3.3/Unions]... [Note: Absent default member initializers, 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. — end note]
Anyways, it seems like at one point this code should have failed, but it was thought to be conforming and that gcc had a bug, and it was claimed to be fixed, but now it should succeed, and it doesn't compile (I may not have the chronology perfect here, it would be interesting to know the full story; figuring it out is one step further than I'd like to take) but I guess I'm just wondering what is the correct behavior?