Home > Mobile >  Union's default constructor is implicitly deleted
Union's default constructor is implicitly deleted

Time:12-21

The following code:

struct non_trivially {
    non_trivially() {};
};

union U {
    bool dummy{false};
    non_trivially value;
};

int main() {
    U tmp;
}

https://godbolt.org/z/1cMsqq9ee

Produces next compiler error on clang (13.0.0):

source>:11:7: error: call to implicitly-deleted default constructor of 'U'
    U tmp;
      ^ <source>:7:19: note: default constructor of 'U' is implicitly deleted because variant field 'value' has a non-trivial default constructor
    non_trivially value;

But successfully compiles using MSVC (19.30).

According to the cppreference it should be a valid code: https://en.cppreference.com/w/cpp/language/union

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 .

In my example there is an alternative in U with a default member initializer so default constructor shouldn't be deleted, but it is. What am I missing?

CodePudding user response:

This is CWG2084. Clang and gcc are just wrong in deleting the default constructor if you provide a default member initializer.

The relevant quote that was added to the standard after the change was adopted (in [class.default.ctor]):

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,
  • [...]
  • X is a union and all of its variant members are of const-qualified type (or array thereof),

(being the only two points that refer to union types, neither one applies, so it should not be implicitly deleted)

The workaround is to user-provide a constructor:

union U {
    constexpr U() : dummy{false} {}
    bool dummy;
    non_trivially value;
};

// Or this also seems to work
union U {
    constexpr U() {}
    bool dummy{false};
    non_trivially value;
};

CodePudding user response:

It's all slightly mysterious. gcc behaves the same as clang.

The standard has this to say (emphasis mine):

Absent default member initializers, if any non-static data member of a union has a non-trivial default constructor, copy constructor, move constructor, copy assignment operator, move assignment operator, or destructor, the corresponding member function of the union must be user-provided or it will be implicitly deleted for the union.

But I think the wording is a bit wooly here. I think what they actually mean is that you must provide an initialiser for the member that has (in your example) a non-trivial constructor, like so:

struct non_trivially {
    non_trivially() {};
};

union U {
    bool dummy;
    non_trivially value { };        // <-- note that I have added an initialiser
};

int main() {
    U tmp;
}

Then, it compiles.

  • Related