15

N3797::9.5/2 [class.union] says:

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

I was trying to understand that note by example:

#include <iostream>
#include <limits>

struct A
{
    A(const A&){ std::cout << "~A()" << std::endl; } //A has no default constructor
};

union U
{
    A a;
};

U u; //error: call to implicitly-deleted default constructor of 'U'

int main()
{

}

DEMO

That behavior isn't quite clear to me. struct A doesn't have implicitly-declared default constructor, because 12.1/4: [class.ctor] says:

If there is no user-declared constructor for class X, a constructor having no parameters is implicitly declared as defaulted (8.4).

Which means struct A doesn't have a non-trivial default constructor (There is no default constructor at all, in particular non-trivial). That's union U doesn't have to have a deleted default constructor. What's wrong?

Pharap
  • 3,826
  • 5
  • 37
  • 51
  • 1
    That's a misleading string you're printing. That aside, at best you've found a loophole in the wording: if the point of `A` is that it cannot be default-constructed, it's surely intended that you cannot bypass that merely by putting it in a union. –  Oct 26 '14 at 11:04
  • 2
    I don’t understand what you’re asking at all: the behaviour seems entirely logical, and in fact *inevitable* to me. What are you expecting? – Konrad Rudolph Oct 26 '14 at 11:07
  • 3
    Your quote is from a note, notes are non-normative. The behavior of union members is the same as a class member in this case, you'd get exactly the same error if `A` were a member of a class. – user657267 Oct 26 '14 at 11:09
  • @KonradRudolph I expected that the programm would compile fine because of in the case the struct doesn't have non-trivial defualt constructor. That's the union doesn't have to declare default constructor as deleted. –  Oct 26 '14 at 11:10
  • @Dmitry Nothing of the sort. If the code compiled, what would you expect `u` to look like? It cannot have been initialised, after all. – Konrad Rudolph Oct 26 '14 at 11:11
  • 1
    @user657267 That sounds like it would make a good answer. –  Oct 26 '14 at 11:11
  • @user657267 Could you provide a normative reference? –  Oct 26 '14 at 11:12
  • @DmitryFucintv What part? The part that a union is a class, or the part that a class that has a non-static data member that cannot be default-constructed doesn't automatically get a usable default constructor (but a deleted one instead)? The latter should be in the 12.1 you've already found (but reading it, I'm unsure of the wording). The former can be found in 9p5 and probably other places: "A union is a class defined with the class-key union [...]" –  Oct 26 '14 at 11:17
  • 1
    @hvd I've found, thanks. But I can't get the point of the following difference: http://coliru.stacked-crooked.com/a/d41171f713fd21e4 and http://coliru.stacked-crooked.com/a/7958d9c5b6e6e40d . Why the later compiles fine, but the first doesn't. –  Oct 26 '14 at 11:23
  • @DmitryFucintv That is a different case, where unions do not and cannot behave like non-union classes. (And it's covered by the wording in 12.1.) A union with a non-static data member with a non-trivial default constructor cannot itself get any default constructor: how would the union know which member to default-construct? Sure, there could be an exception for a union with a single member, but why use a union at all then? –  Oct 26 '14 at 11:27

2 Answers2

7

The relevant wording is in C++11 [class.ctor]p5 (emphasis mine):

A default constructor for a class X is a constructor of class X that can be called without an argument. If there is no user-declared constructor for class X, a constructor having no parameters is implicitly declared as defaulted (8.4). [...] 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,

[...]

  • any direct or virtual base class, or non-static data member with no brace-or-equal-initializer, has class type M (or array thereof) and either M has no default constructor or overload resolution (13.3) as applied to M's default constructor results in an ambiguity or in a function that is deleted or inaccessible from the defaulted default constructor, or

[...]

Your class A has no default constructor, so a defaulted default constructor (whether implicit or explicit) for a class X (whether union or non-union) containing a non-static data member of type A without an initialiser leads to the default constructor for X being deleted. It has to: there's simply no way for the compiler to generate any other default constructor.

As for your follow-up question in the comments:

If instead of A not having a default constructor, it has a non-trivial default constructor, then there is a difference between using that in a union and in a non-union class, and that is also part of [class.ctor]p5: it is the first bullet point that I included, without emphasis, in my earlier quote.

Community
  • 1
  • 1
5

In your example, the problem is not that your code has no non trivial default constructor, but that it has a copy constructor.

But generally, a union has several members: "at most one of the non-static data members can be active at any time, that is, the value of at most one of the non-static data members can be stored in a union at any time" (9.5/1).

Suppose you have a union with several members some of them having non trivial constructors or copy constructors:

union W {
    A a; 
    int i; 
};

When you would create an object:

W w;  

how should this object be default constructed ? Which member should be the active one ? How should such an object be default-copied ? Is it the A or the int that should be constructed/copied ?

This is why the standard foresses that your union has a deleted default constructor (copy constructor in your case). It should be sufficient to user-provide the missing default function.

union W
{
    int i;
    A a;
    W() { /*...*/ }
    W(const W&c) { /*...*/ }
};

This paper explains the rationale and the wording of C++11 on the topic in its full details.

Important remark: Unfortunately, unrestricted unions are not supported by MSVC13 : it still does not accept ANY member having ANY of the non-trivial default function user defined. GCC accepts it since 4.6 and clang since 3.1.

Johnny Willemsen
  • 2,942
  • 1
  • 14
  • 16
Christophe
  • 68,716
  • 7
  • 72
  • 138