vendredi 18 mai 2018

C++ Default constructors in union with variant member with non-trivial default constructor

I recently read a description of default constructors for unions: Default Constructor

There is a following rule:

Blockquote Deleted implicitly-declared default constructor: [...] T is a union with at least one variant member with non-trivial default constructor, and no variant member of T has a default member initializer.[...]

Then I decided to make an exercise and verify the rule.

struct Member {
 public:
  // Member() : mX(0) {}
  virtual int GetX() {
    return mX;
  }
  int mX;
};

union DefaultConstructor {
  int mA;
  Member mMember;
  int GetA();
};

With use of gcc v5.3.1 (I know it is pretty old) I receive expected error:

> ../src/DefaultConstrcutors.cpp: In function ‘void
> Test_DefaultConstructors()’: ../src/DefaultConstrcutors.cpp:26:22:
> error: use of deleted function
> ‘DefaultConstructor::DefaultConstructor()’    DefaultConstructor foo;
>                       ^ In file included from ../src/DefaultConstrcutors.cpp:19:0:
> ../src/DefaultConstructors.h:155:7: note:
> ‘DefaultConstructor::DefaultConstructor()’ is implicitly deleted
> because the default definition would be ill-formed:  union
> DefaultConstructor {
>        ^ ../src/DefaultConstructors.h:157:10: error: union member ‘DefaultConstructor::mMember’ with non-trivial ‘Member::Member()’   
> Member mMember;
>           ^

Ok, so according to rule, if I provide a default member initializer for a variant member, then it should compile. So I've changed union definition to:

union DefaultConstructor {
      int mA = 0;
      Member mMember;
      int GetA();
    };

And now it should compile, but I've received the same error.

Next step was to provide default initializer for a mMember instead of mA (only one union variant member may have default initializer).

union DefaultConstructor {
      int mA;
      Member mMember{};
      int GetA();
    };

Now it compiles.

The question is: why it didn't compile in second case, when mA had default initializer? According to mentioned rule it should be possible. What more similar rule is provided here: Union declaration

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 .

Anyone has an idea why doesn't it work?

Greetings, Piotr

Aucun commentaire:

Enregistrer un commentaire