tl; dr: последние два утверждения в вашем коде выше всегда будут вызывать неопределенное поведение, просто приведение указателя на объединение к указателю на один из его типов-членов, как правило, хорошо, потому что на самом деле ничего не делает (этов худшем случае неопределенное, но никогда не определяемое поведение; примечание: речь идет только о самом приведении, использование результата преобразования для доступа к объекту - это совсем другая история).
В зависимости от того, чтоT
заканчивается тем, что Struct<T>
потенциально может быть структурой стандартного макета [class.prop] / 3 , в этом случае
T *aSP = reinterpret_cast<T *>(aS);
будет четко определено, потому чтоStruct<T>
будет взаимозаменяемым указателем с его первым членом (который имеет тип T
) [basic.compound] /4.3.Выше reinterpret_cast
эквивалентно [expr.reinterpret.cast] / 7
T *aSP = static_cast<T *>(static_cast<void *>(aS));
, которое вызовет преобразование массива в указатель [conv.array] , в результате Struct<T>*
указывает на первый элемент aS
.Этот указатель затем преобразуется в void*
(через [expr.static.cast] / 4 и [conv.ptr] / 2 ), который затем преобразуется в T*
, что будет разрешено через [expr.static.cast] / 13 :
Значение типа «указатель на cv1 void
» можетпреобразовать в значение типа «указатель на cv2 T
», где T
- это тип объекта, а cv2 - такая же квалификация cv, как и выше, или cv-квалификация, чем, CV1 .Если исходное значение указателя представляет адрес A
байта в памяти и A
не удовлетворяет требованию выравнивания T
, то результирующее значение указателя не определено. В противном случае, если исходное значение указателя указывает на объект a
, и существует объект b
типа T
(игнорирующий квалификацию cv), который может быть преобразован в указатель с a
, результатом будетуказатель на b
.В противном случае значение указателя при преобразовании не изменится.
Аналогично,
T *aUP = reinterpret_cast<T *>(aU);
будет четко определен в C ++ 17, если Union<T>
является стандартной компоновкойunion и выглядит хорошо определенным в целом в новой версии C ++, основанной на текущем стандартном черновике, где union и один из его членов всегда взаимозаменяемы с указателем [basic.compound] /4.2
Все вышеперечисленное не имеет значения, однако, потому что
T valueS = aSP[9];
и
T valueU = aUP[9];
будут вызывать неопределенное поведение, несмотря ни на что.aSP[9]
и aUP[9]
(по определению) такие же, как *(aSP + 9)
и *(aUP + 9)
соответственно [expr.sub] / 1 .Арифметика указателя в этих выражениях подчиняется [expr.add] / 4
Когда выражение J
, имеющее целочисленный тип, добавляется или вычитается из выражения P
типа указателя, результат имеет тип P
.
- Если
P
оценивается как нулевое значение указателя, а J
оценивается как 0, результат является нулевым значением указателя. - В противном случае, если
P
указывает на элемент x[i]
объекта массива x
с n элементами, выражения P + J
и J + P
(где J
имеет значение j ) указывает на (возможно, гипотетический) элемент x[i+j]
, если 0≤i + j≤n , а выражение P - J
указывает на (возможно, гипотетический)) element x[i−j]
if 0≤i − j≤n . - В противном случае поведение не определено.
aSP
и aUP
не указывают на элемент массива.Даже если aSP
и aUP
будут взаимозаменяемыми с T
, вам будет разрешено только получить доступ к элементу 0 и вычислить адрес (но не доступа) элемента 1 гипотетического одноэлементного массива…