You cannot do this: &reinterpret_cast<PunnerToUInt32*>(&x)
The rules on reinterpret_cast state:
When a pointer or reference to object whose dynamic type is DynamicType is reinterpret_cast (or C-style cast) to a pointer or reference to object of a different type AliasedType, the cast always succeeds, but the resulting pointer or reference may only be used to access the object if one of the following is true:
AliasedType is (possibly cv-qualified) DynamicType
AliasedType and DynamicType are both (possibly multi-level, possibly cv-qualified at each level) pointers to the same type T
AliasedType is the (possibly cv-qualified) signed or unsigned variant of DynamicType
AliasedType is an aggregate type or a union type which holds one of the aforementioned types as an element or non-static member (including, recursively, elements of subaggregates and non-static data members of the contained unions): this makes it safe to obtain a usable pointer to a struct or union given a pointer to its non-static member or element.
AliasedType is a (possibly cv-qualified) base class of DynamicType
AliasedType is char or unsigned char: this permits examination of the object representation of any object as an array of unsigned char
Because none of these are true for the combination of DynamicType being float and AliasedType being PunnerToUInt32 the pointer may not be used to access the object, which you are doing. Making the behavior undefined.
For more information see: Why Doesn't reinterpret_cast Force copy_n for Casts between Same-Sized Types?
EDIT:
Breaking down the 4th bullet int bite size chunks yields:
- "
AliasedType"
Here taken to be PunnerToUInt32
"is an aggregate type or a union type"
PunnerToUInt32 qualifies since it meets the qualifications of an aggregate type:
- array type
- class type (typically,
struct or union), that has
- no private or protected non-static data members
- no user-provided constructors, including those inherited from public bases (explicitly defaulted or deleted constructors are allowed)
- no virtual, private, or protected base classes
- no virtual member functions
"which holds one of the aforementioned types as an element or non-static member (including, recursively, elements of subaggregates and non-static data members of the contained unions)"
Again PunnerToUInt32 qualifies because of it's float fl member
- "this makes it safe to obtain a usable pointer to a struct or union"
This is the final correct part as AliassedType is a PunnerToUInt32
- "given a pointer to its non-static member or element"
This is a violation, because the DynamicType which is x is not a member of PunnerToUInt32
Because of the violation of part 5 operating on this pointer is undefined behavior.
If you care for some recommended reading you can check out Empty Base Optimization if not I'll give you the primary relevance here:
Empty base optimization is required for StandardLayoutTypes in order to maintain the requirement that the pointer to a standard-layout object, converted using reinterpret_cast, points to its initial member
Thus you could exploit reinterpret_cast's 4th bullet by doing this:
PunnerToUInt32 x = {13, 42.0F};
auto y = reinterpret_cast<PunnerToUInt32*>(&x.ui32);
Live Example