Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Default constructor cannot be referenced when using std::string in union member of a struct

I have a very basic struct that has an enum and a union.

typedef struct
{
    enum v{a,b,c}v;
    union w{
        int a;
        bool b;
        std::string c;
    }w;

}Data_Set2;

int main()
{
Data_Set2 val; // Shows errror that the default constructor cannot be referenced
return 0;
}

On using such a struct I get the Error Code C2280 that the default constructor cannot be referenced. When I declare the struct in a slightly different way as following

typedef struct
{
    enum v{a,b,c}v;
    union w{
        int a;
        bool b;
        std::string c;
    }; // changed here.

}Data_Set2;

The Error no longer exists. I fail to understand the reason behind this. Could anyone explain why this happens

like image 524
D_wanna_B_coder Avatar asked Dec 17 '22 18:12

D_wanna_B_coder


1 Answers

From https://en.cppreference.com/w/cpp/language/union (or see standard):

If a union contains a non-static data member with a non-trivial special member function (copy/move constructor, copy/move assignment, or destructor), that function is deleted by default in the union and needs to be defined explicitly by the programmer.

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 .

At most one variant member can have a default member initializer.

In your case this means that you have to explicitly declare a constructor and destructor. Change your code to:

typedef struct
{
    enum v{a,b,c} v;
    union w{
        int a;
        bool b;
        std::string c;
        w() {}       // Explicit constructor definition
        ~w() { };    // Explicit destructor definition
} w;

} Data_Set2;

This should work.

As already stated in my comment, you should however have a look at std::any and std::variant. The latter provides type-safe unions and would probably be the better choice in your case. Note that your compiler (apparently MSVC) needs to support C++17.

EDIT: As commented by eerorika, you will need to make sure that you only call it on the currently active member. The reference linked in the beginning shows an example for a string/vector union and how it introduces many pitfalls for undefined behavior. So unless you're just trying to understand what's happening behind the scenes or using POD types, I'd advise you work with std::variant instead.

like image 166
andreee Avatar answered Dec 20 '22 06:12

andreee