I think it's defined behavior, assuming Pair
is standard-layout. Otherwise, it's undefined behavior.
First, a standard layout class and its first member share an address. The new wording in [basic.compound] (which clarifies earlier rules) reads:
Two objects a and b are pointer-interconvertible if:
* [...]
* one is a standard-layout class object and the other is the first non-static data member of that object,
or, [...]
* [...]
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
(5.2.10).
Also from [class.mem]:
If a standard-layout class object has any non-static data members, its address is the same as the address
of its first non-static data member. Otherwise, its address is the same as the address of its first base class
subobject (if any).
So the reinterpret_cast
from A
to Pair
is fine. If then function
only ever access the a
object, then that access well-defined, as the offset of A
is 0, so the behavior is equivalent to having function
take an A&
directly. Any access to the b
would be undefined, obviously.
However, while I believe the code is defined behavior, it's a bad idea. It's defined behavior NOW, but somebody someday might change function
to refer to pair.b
and then you're in a world of pain. It'd be a lot easier to simply write:
void function(A& a) { ... }
void function(Pair& p) { function(p.a); }
and just call function
directly with your a
.