Take e.g. the following code:
class B {
void *ptr = nullptr;
public:
auto get() { return ptr; }
};
class D : public B {};
union U {
B b;
D d;
};
void *func() {
U u{.d = D{}};
return u.b.get(); // ???
}
I am wondering if the line marked with ??? has undefined behavior.
The C++20 standard says in [class.union.general]:
In a union, a non-static data member is active if its name refers to an object whose lifetime has begun and has not ended ([basic.life]). At most one of the non-static data members of an object of union type can be active at any time, that is, the value of at most one of the non-static data members can be stored in a union at any time.
Since d is the active data member at this point, this would imply that it's not allowed to read b. But b and d are layout-convertible, so we know that we could still access it's data member by [class.mem.general]:
In a standard-layout union with an active member of struct type T1, it is permitted to read a non-static data member m of another union member of struct type T2 provided m is part of the common initial sequence of T1 and T2; the behavior is as if the corresponding member of T1 were nominated.
I don't think that this is relevant though since I want to access a member function, not a data member. (At least not directly.)
Now the B base class subobject of d is the first subobject of d and therefore pointer-interconvertible with d, which is pointer-interconvertible with u and therefore b. So we end up with two pointer-interconvertible objects of the same type.
Is there some rule which allows this access based on that?
The only rule I could find about that is [basic.compound]:
If two objects are pointer-interconvertible, then they have the same address, and it is possible to obtain a pointer to one from a pointer to the other via a
reinterpret_cast.
Which only seems to allow reinterpret_cast<B*>(&u.b)->get() which feels silly.
So is there some rule which allows this or does it rely on undefined behavior and/or compiler extensions?
(I am mostly interested in C++20 or newer drafts)