Standard says:
[array.overview]
... An array is a contiguous container. ...
An array is an aggregate that can be list-initialized with up to N elements whose types are convertible to T.
array<T, N>
is a structural type if T is a structural type.
The standard doesn't explicitly say what members std::array
has. As such, we technically cannot assume that it has a common initial sequence with any type.
From the shown requirements placed on std::array
we might reasonably assume that it has a member of type T[N]
. Let's explore whether there is a common initial sequence if this assumption is correct.
[class.mem.general]
The common initial sequence of two standard-layout struct ([class.prop]) types is the longest sequence of non-static data members and bit-fields in declaration order, starting with the first such entity in each of the structs, such that corresponding entities have layout-compatible types, ...
[basic.types.general]
Two types cv1 T1 and cv2 T2 are layout-compatible types if T1 and T2 are the same type, layout-compatible enumerations, or layout-compatible standard-layout class types.
std::uint8_t[32]
and std::uint32_t[8]
are not the same type (ignoring cv qualifiers), nor are they enumerations nor classes. Therefore they are not layout-compatible types, and therefore they cannot be part of the same common initial sequence.
Conclusion: No, there is no common initial sequence whether we can safely assume the member of std::array
or not.
I write .words and read .bytes
The behaviour of the program is undefined.
Given that you want to read it as an array of (unsigned) char, it would be safe to reinterpret instead of union punning:
static constexpr std::size_t size = 32;
using word = std::uint32_t;
std::array<word, size / sizeof(word)> words {
1, 2, 3, 4,
};
std::uint8_t* bytes = reinterpret_cast<std::uint8_t*>(words.data());
And, if you want a range:
std::span<std::uint8_t, size> bytes_range {
bytes, bytes + size,
};