Given an array of some union type, if the following conditions are met:
union in the array is the same,sizeof each member within the union is the same, andalignof each member within the union is the sameStandardLayoutTypethen are the following actions safe:
For example, consider the following code-segment:
template<typename T, typename U>
union storage_type
{
T value0;
U value1;
};
static_assert( sizeof(int) == sizeof(float), "" );
static_assert( alignof(int) == alignof(float), "" );
storage_type<int,float> storage[] = { {1}, {2}, {3} };
// the active type of all storage_type is 'int', so cast to int*
// to be treated as an array of ints
auto* array = reinterpret_cast<int*>(&storage[0]);
assert( array[0] == 1 );
assert( array[1] == 2 );
assert( array[2] == 3 );
I'm interested in what the C++ Standard has to explicitly say about such a case. I know that StandardLayoutTypes are safe to cast to the first member of the structure or active element of the union, so I suspect that my first cast is safe; but I'm unsure if this would hold true for an array, and treating it like an array of the active type.
I tried doing some searching, both on SO and in the C++ standard (N4660 C++17 draft) -- but I didn't have any luck
Note: This question is not about whether this will work in practice due to compilers having C compatibility; this is strictly a question on whether this invokes UB in C++, and whether it violates strict-aliasing rules.
In theory, this can fail. As per standard:
The size of a union is sufficient to contain the largest of its data members.
So, in theory, sizeof(my_union) and sizeof(largest_member) might differ.
If you static_assert() that it's the same, then:
int* array = &storage[0].value0;
... does it and you're UB-free due to how array indexing works.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With