Так как С++ 11 std::complex<T>[n]
гарантированно является алиасифицированным как T[n*2]
, с четко определенными значениями. Это именно то, чего можно было бы ожидать для любой основной архитектуры. Является ли эта гарантия достижимой со стандартным С++ для моих собственных типов, скажем struct vec3 { float x, y, z; }
или это возможно только при специальной поддержке компилятора?
`std:: complex <T> [n]` и `T [n * 2]` тип сглаживания
Ответ 1
TL; DR. Компилятор должен проверить reinterpret_cast
и выяснить, что задействованы (стандартная библиотека) специализации std::complex
. Мы не можем соответствующим образом имитировать семантику.
Я думаю, что довольно ясно, что обработка трех отдельных элементов как элементов массива не будет работать, поскольку арифметика указателей на указатели на них крайне ограничена (например, добавление 1 дает указатель в конце).
Итак, пусть vec3
содержит массив из трех int
.
Даже тогда базовый reinterpret_cast<int*>(&v)
, который вам неявно нужен (где v
является vec3
), не оставляет вас указателем на первый элемент. См. Исчерпывающие требования к указатель-взаимопревращение:
Два объекта
a
иb
являются взаимно обратимыми для указателей, если:
они являются одним и тем же объектом, или
один представляет собой объект объединения стандартного макета, а другой - нестатический член данных этого объекта ([class.union]) или
один является объектом класса стандартного макета, а другой является первым нестатическим членом данных этого объекта или, если объект не имеет нестатические элементы данных, первый подобъект базового класса этого объекта ([class.mem]) или
существует объект
c
такой, чтоa
иc
являются взаимно обратимыми, аc
иb
являются указатель равноценно.Если два объекта взаимно конвертируемы, то они имеют одинаковые адрес, и можно получить указатель на один из указателя к другому через a
reinterpret_cast
. [Примечание: Объект массива и его первый элемент не является взаимно конвертируемым, хотя они имеют тот же адрес. - конец примечания]
Это совершенно однозначно; в то время как мы можем получить указатель на массив (являющийся первым членом), а в то время как взаимная конвертация указателя транзитивна, мы не можем получить указатель на свой первый элемент.
И, наконец, даже если вам удалось получить указатель на первый элемент вашего массива-члена, если у вас был массив vec3
s, вы не сможете пройти все массивы-члены с помощью простых указателей указателя, поскольку мы получаем указатели прошлый конец массивов между ними. также не решает эту проблему, поскольку объекты, с которыми связаны указатели, не имеют общего хранилища (cf [ptr.launder] для специфики).
Ответ 2
Это возможно только при особой поддержке компилятора.
Союзы не получают вас там, потому что общий подход имеет поведение undefined, хотя есть исключения для исходных последовательностей, совместимых с макетами, и вы можете проверить объект через unsigned char*
как особый случай. Что это, тем не менее.
Интересно, что, если мы не примем широкое и бесполезное значение "ниже", стандарт технически противоречив в этом отношении:
[C++14: 5.2.10/1]:
[..] Ниже перечислены преобразования, которые могут быть выполнены явно с использованием reinterpret_cast. Никакое другое преобразование не может быть выполнено явно с использованием reinterpret_cast.
Случай для complex<T>
не упоминается. Наконец, правило, о котором вы говорите, вводится гораздо позже, в [C++14: 26.4/4]
.
Ответ 3
Я думаю, что это сработало бы для одного vec3
, если бы ваш тип содержал float x[3]
, а вы обеспечили sizeof(vec3) == 3*sizeof(float) && is_standard_layout_v<vec3>
. Учитывая эти условия, стандарт гарантирует, что первый член имеет нулевой сдвиг, поэтому адрес первого float
является адресом объекта, и вы можете выполнить арифметику массива, чтобы получить другие элементы в массиве:
struct vec3 { float x[3]; } v = { };
float* x = reinterpret_cast<float*>(&v); // points to first float
assert(x == v.x);
assert(&x[0] == &v.x[0]);
assert(&x[1] == &v.x[1]);
assert(&x[2] == &v.x[2]);
То, что вы не можете сделать, это обработать массив vec3
как массив поплавков в три раза больше длины. Арифметика массива в массиве внутри каждого vec3
не позволит вам получить доступ к массиву в следующем vec3
. CWG 2182 здесь.