Mine
Mine

Reputation: 4241

Return brace-enclosed initializer list as struct

Giving below simplified code compiled with g++ -c test.cpp or g++ -std=c++17 -c test.cpp

#include <cstddef>

struct sd_bus_vtable {
        union {
                struct {
                        size_t element_size;
                } start;
                struct {
                        const char *member;
                        const char *signature;
                } signal;
        } x;
};

sd_bus_vtable get()
{
    return {
        .x = {
            .signal = {
                .member = "",
                .signature= "",
            }
        }
    };
}

It compiles fine on GCC 9.2.0 and clang 5/6, but fails on 8.3.0 or 7.4.0 with below error message:

test.cpp:25:5: error: could not convert ‘{{{"", ""}}}’ from ‘<brace-enclosed initializer list>’ to ‘sd_bus_vtable’
     };

To work around it, the function get() could be changed as below, but it looks not so clean...

sd_bus_vtable get()
{
    struct sd_bus_vtable t = {
        .x = {
            .signal = {
                .member = "",
                .signature= "",
            }
        }
    };
    return t;
}

The question is, is the above code valid or not? If yes, does it trigger some bug in GCC that is fixed in GCC9?

Upvotes: 3

Views: 544

Answers (1)

M.M
M.M

Reputation: 141574

The designated initializer syntax is not in Standard C++ yet. It is scheduled to be included in C++20 however that has not yet been finalized or published.

So you are relying on the compiler supporting this upcoming feature as an extension.

In published C++ standards there is no way to give an initializer like this for a union member other than the first one . (You can have a default member initializer in the class definition).

In the meantime the following code would work:

sd_bus_vtable get()
{
    sd_bus_vtable r{};
    r.x.signal = {"", ""};
    return r;    
}

Note: This method (using the assignment operator to switch the active member of the union) only works if all of the union members have trivial constructors and destructors. Otherwise you need to manually destroy and create .

Also it's possible to omit the name x (this is called anonymous union), then the names of the union members are accessible as if they were members of the enclosing struct.

Upvotes: 3

Related Questions