Graeme
Graeme

Reputation: 4592

Constructing struct within union

I have created a union comprising a uint64_t and a struct. I would like the union constructor to construct the inner struct but I can't seem to get it working. Here's a couple of variations I have tried:

union subid_u
{
    inline subid_u(uint32_t gid_, uint32_t sid_)
        : detail.gid(gid_), detail.sid(sid_) {}

    struct detail_t
    {
        uint32_t gid;
        uint32_t sid;
    };

    detail_t    detail;
    uint64_t    subscriptionID;
};
//main.cpp: In constructor 'subid_u::subid_u(uint32_t, uint32_t)':
//main.cpp:7: error: expected `(' before '.' token
//main.cpp:7: error: expected `{' before '.' token


union subid_u
{
    inline subid_u(uint32_t gid_, uint32_t sid_)
        : detail(gid_, sid_) {}

    struct detail_t
    {
        inline detail_t(uint32_t g, uint32_t s)
            : gid(g), sid(s) {}

        uint32_t gid;
        uint32_t sid;
    };

    detail_t    detail;
    uint64_t    subscriptionID;
};
//main.cpp:18: error: member 'subid_u::detail_t subid_u::detail' with constructor not allowed in union

Upvotes: 2

Views: 2612

Answers (2)

Lightness Races in Orbit
Lightness Races in Orbit

Reputation: 385134

You can't initialise members of members like that: you'd have to have a constructor in detail and invoke that from subid_u's ctor-initialiser.

union subid_u
{
    inline subid_u(uint32_t gid, uint32_t sid) : detail(gid, sid) {}

    struct detail_t
    {
        detail_t(uint32_t gid, uint32_t sid) : gid(gid), sid(sid) {}
        uint32_t gid;
        uint32_t sid;
    };

    detail_t    detail;
    uint64_t    subscriptionID;
};

So you tried that, and got your second error. Yes, it doesn't make sense for a complex object to be in a union.

Instead of initialisation, use assignment (and I'd never usually recommend this!)

union subid_u
{
    inline subid_u(uint32_t gid_, uint32_t sid_) {
        detail.gid = gid_;
        detail.sid = sid_;
    }

    struct detail_t
    {
        uint32_t gid;
        uint32_t sid;
    };

    detail_t    detail;
    uint64_t    subscriptionID;
};

Problem solved...?

In C++0x you'll be able to do this:

union subid_u
{
    inline subid_u(uint32_t gid, uint32_t sid) : detail{gid, sid} {}

    struct detail_t
    {
        uint32_t gid;
        uint32_t sid;
    };

    detail_t    detail;
    uint64_t    subscriptionID;
};

Upvotes: 5

Erik
Erik

Reputation: 91260

You can't use the initializer list - you'll need to use assignment in the ctor.

union subid_u
{
    subid_u(uint32_t gid_, uint32_t sid_) {
      detail.gid = gid_;
      detail.sid = sid_;
    }
    ...
};

This limitation is a result of combining two facts:

9.5/1 snippet:

An object of a class with a non-trivial constructor (12.1), a non-trivial copy constructor (12.8), a non-trivial destructor (12.4), or a non-trivial copy assignment operator (13.5.3, 12.8) cannot be a member of a union, nor can an array of such objects.

12.6.2/1 snippet:

In the definition of a constructor for a class, initializers for direct and virtual base subobjects and nonstatic data members can be specified by a ctor-initializer,

So, you can only initialize direct member variables in an initializer list (allowing you to initialize detail but not detail's members), and you cannot have a class with a constructor as a union member.

Upvotes: 2

Related Questions