Search code examples
c++c++11structunions

Anonymous union and struct


How would you go about doing this in standard C++11/14 ? Because if I'm not mistaken this isn't standard compliant code with the anonymous structs.

I wish to access the members the same way as you would with this.

template <typename some_type>
struct vec
{
    union {
        struct { some_type x, y, z; };
        struct { some_type r, g, b; };

        some_type elements[3];
    };
};

Solution

  • Yes, neither C++11 nor C++14 allow anonymous structs. This answer contains some reasoning why this is the case. You need to name the structs, and they also cannot be defined within the anonymous union.

    §9.5/5 [class.union]

    ... The member-specification of an anonymous union shall only define non-static data members. [ Note: Nested types, anonymous unions, and functions cannot be declared within an anonymous union. —end note ]

    So move the struct definitions outside of the union.

    template <typename some_type>
    struct vec
    {
        struct xyz { some_type x, y, z; };
        struct rgb { some_type r, g, b; };
    
        union {
            xyz a;
            rgb b;
            some_type elements[3];
        };
    };
    

    Now, we require some_type to be standard-layout because that makes all the members of the anonymous union layout compatible. Here are the requirements for a standard layout type. These are described in section §9/7 of the standard.

    Then, from §9.2 [class.mem]

    16   Two standard-layout struct (Clause 9) types are layout-compatible if they have the same number of non-static data members and corresponding non-static data members (in declaration order) have layout-compatible types (3.9).
    18   If a standard-layout union contains two or more standard-layout structs that share a common initial sequence, and if the standard-layout union object currently contains one of these standard-layout structs, it is permitted to inspect the common initial part of any of them. Two standard-layout structs share a common initial sequence if corresponding members have layout-compatible types and either neither member is a bit-field or both are bit-fields with the same width for a sequence of one or more initial members.

    And for the array member, from §3.9/9 [basic.types]

    ... Scalar types, standard-layout class types (Clause 9), arrays of such types and cv-qualified versions of these types (3.9.3) are collectively called standard-layout types.

    To ensure that some_type is standard layout, add the following within the definition of vec

    static_assert(std::is_standard_layout<some_type>::value, "not standard layout");
    

    std::is_standard_layout is defined in the type_traits header. Now all 3 members of your union are standard layout, the two structs and the array are layout compatible, and so the 3 union members share a common initial sequence, which allows you to write and then inspect (read) any members belonging to the common initial sequence (the entire thing in your case).