由于C ++ 11 std::complex<T>[n]
可以保证为T[n*2]
的可替换,因此具有明确定义的值。这正是人们对任何主流架构的期望。对于我自己的类型,使用标准C ++可以实现这种保证吗,比如struct vec3 { float x, y, z; }
,还是只有在编译器的特殊支持下才能实现?
答案 0 :(得分:9)
TL; DR :编译器必须检查reinterpret_cast
并确定涉及std::complex
的(标准库)特化。我们不能一致地模仿语义。
我认为很明显将三个不同的成员视为数组元素是行不通的,因为指向它们的指针算法受到极大限制(例如,加1会产生pointer past-the-end)。 / p>
因此,我们假设vec3
包含三个int
的数组。
即使这样,你隐含需要的基础reinterpret_cast<int*>(&v)
(v
是vec3
)也不会给你留下指向第一个元素的指针。请参阅pointer-interconvertibility上的详尽要求:
如果出现以下情况,则
a
和b
两个对象指针可互换:
它们是同一个对象,或
一个是标准布局联合对象,另一个是该对象的非静态数据成员([class.union]),或
一个是标准布局类对象,另一个是该对象的第一个非静态数据成员,或者,如果该对象没有 非静态数据成员,该对象的第一个基类子对象 ([class.mem]),或
存在一个对象
c
,a
和c
是指针可互换的,c
和b
是 指针的互变的。如果两个对象是指针可互换的,那么它们具有相同的 地址,并且可以从指针获得指向一个的指针 通过
reinterpret_cast
到另一个。 [注意:数组对象 并且它的第一个元素不是指针可互换的,尽管如此 他们有相同的地址。 - 结束说明]
这是非常明确的;虽然我们可以得到一个指向数组的指针(作为第一个成员),虽然指针 - 互换性是可传递的,但我们无法获得指向其第一个元素的指针。
最后,即使你设法获得指向成员数组的第一个元素的指针,如果你有一个vec3
数组,你也不能遍历所有成员数组使用简单的指针增量,因为我们在两者之间获得了数组的指针。清洗器也没有解决这个问题,因为指针所关联的对象不共享任何存储空间(参见[ptr.launder]了解详细信息)。
答案 1 :(得分:4)
如果您的类型包含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与此相关。