1

I have following code which generates error at compile time:

struct s { int three; };

union alias {
    struct { int one; };
    struct { int two; };
    struct : s {};
};

int main()
{
    alias a;
    a.one = 1;   // OK
    a.two = 2;   // OK
    a.three = 3; // error: 'union alias' has no member named 'three'
    return 0;
}

For some reason members of inherited struct in the union are inaccessible. The main purpose of this code is to provide an aliases to members of struct s.

Why compiler doesn't see members of inherited structure? Any options to make them accessible?

timrau
  • 22,578
  • 4
  • 51
  • 64
Oleksandr
  • 419
  • 3
  • 14
  • 1
    Type-punning with unions is UB by the standard. Use with care. – Evg Jan 09 '20 at 14:32
  • 1
    You've merely defined the structs within the union, not defined the union members. You need data member definitions, and then your anonymous union will work. The fact that `a.one` and `a.two` are "OK" seems very, very fishy; in fact, I can't get it to compile at all. – Bartek Banachewicz Jan 09 '20 at 14:34
  • 1
    @StoryTeller-UnslanderMonica, Clang: "warning: declaration does not declare anything". – Evg Jan 09 '20 at 14:36
  • What do you thing this `struct { int one; };` should actually declare? – Daniel Langr Jan 09 '20 at 14:40
  • 7
    It should be noted that anonymous structs are not a part of C++; they are a compiler extension. So exactly how they interact with inheritance is... debatable and not governed by the standard. – Nicol Bolas Jan 09 '20 at 14:41
  • @Evg I'm not trying to make type punning. Actually this is simplified version of code with templates which attempts to provide only name aliases for members of `struct s` without changing type[s]. – Oleksandr Jan 09 '20 at 14:51
  • 2
    @Evg accessing inactive members of a union is allowed given that the inactive member has a common initial sequence with the active member and you use only that common initial sequence. – Guillaume Racicot Jan 09 '20 at 14:56
  • @NicolBolas very good point. I'll consider to avoid this approach. – Oleksandr Jan 09 '20 at 14:56
  • @GuillaumeRacicot, thanks for this note. But is it a common sequence in this case (taking into account the comment by Nicol Bolas)? – Evg Jan 09 '20 at 14:59
  • 1
    @Evg I would say yes, but I rarely have to play with this particular extension – Guillaume Racicot Jan 09 '20 at 15:02
  • @stunpix you'd probably be best off writing a more usual facade (either a ref-semantics wrapper or just free functions) if this is just for interface compatibility. It's a bit of an X/Y problem I suppose. – Bartek Banachewicz Jan 09 '20 at 15:03

1 Answers1

3

Okay, after a bit of head-scratching, I think I can explain this correctly. Well, to start things off, this is Illegal As Heck (tm).

A struct defined within a union confuses the compiler a bit. If a struct def is followed by a name, a new variable of type of such struct would normally be created, but C++ explicitly disallows anonymous structs. If you omit that name, it could mean two things - either an anonymous struct type is created and then immediately dropped (which meets with a -Wpedantic warning), or, as seems to be happening with GCC, it considers it a creation of an anonymous member of an anonymous type, which is a non-standard extension:

union alias {
    struct { int one; };     // anonymous member of an anonymous type
    struct a { int two };    // no member, just def of "struct a"
    struct { int three; } b; // named (b) member of type anonymous struct
};

All in all, you can't really expect this to work... unless you create the union members with explicit type and data member names:

struct s { int three; };

union alias {
    struct A { int one; };
    struct B { int two; };
    struct C : s { };

    A a;
    B b;
    C c;
};

int main() {
    alias a;
    a.a.one = 1;   // OK
    a.b.two = 2;   // OK
    a.c.three = 3; // OK
}

The whole anonymous union member thing is still a bit puzzling to me, as I can't figure out anything in the standard that would make this work.

Bartek Banachewicz
  • 38,596
  • 7
  • 91
  • 135
  • Thanks for your time. I think I'll avoid this approach, due to fact that anonymous structs are non-standard language extension. – Oleksandr Jan 09 '20 at 15:03