Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I create an instance of this tagged union? Compiler errors about deleted constructor

Tags:

c++

Here's my tagged union:

struct UniformVariant
{
    enum class UNIFORM_TYPE {FLOAT, INT32, VEC2, VEC3, VEC4, MAT4} type;
    union
    {
        float f;
        int i;
        glm::vec2 v2;
        glm::vec3 v3;
        glm::vec4 v4;
        glm::mat4 m4;
    } value;
};

If I try to use it like so:

void some_function()
{
    UniformVariant v;
    some_other_function(v);
}

I get a compilation error use of deleted function 'UniformVariant::UniformVariant()'

It further says that it was implicitly deleted because the default definition would be ill-formed. So I've tried adding a constructor to the UniformVariant

UniformVariant() : value(0.0f), type(UNIFORM_TYPE::FLOAT) { };

But similar issues. I believe it has to do with the inclusion of class types in the union; but I can't figure out the syntax to use this correctly.

like image 720
NeomerArcana Avatar asked Feb 09 '23 18:02

NeomerArcana


1 Answers

From a note in [class.union]:

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.

One of the types in that union has a non-trivial default constructor, so you can't default-construct the union. Consider this simpler reproduction:

struct X {
    X() { }  
};

struct Y {
    union {
        float f;
        X x;
    } value;
};

int main()
{
    Y y;
}

X has a non-trivial default constructor, so Y::Y() is implicitly deleted because the anonymous union default constructor is implicitly deleted.

However, you can just provide your own default constructor for that union:

union U {
    U() : f(0.f) { }

    float f;
    X x;
} value;

And now the example compiles.

However, if you're just implementing your own tagged union, I would highly recommend using Boost.Variant. It's quite useful and solves exactly this problem.

like image 146
Barry Avatar answered Feb 13 '23 04:02

Barry