`std :: complex <t> [n]`和`T [n * 2]`类型别名

时间:2017-02-23 15:38:38

标签: c++ language-lawyer strict-aliasing type-punning

由于C ++ 11 std::complex<T>[n]可以保证为T[n*2]的可替换,因此具有明确定义的值。这正是人们对任何主流架构的期望。对于我自己的类型,使用标准C ++可以实现这种保证吗,比如struct vec3 { float x, y, z; },还是只有在编译器的特殊支持下才能实现?

2 个答案:

答案 0 :(得分:9)

TL; DR :编译器必须检查reinterpret_cast并确定涉及std::complex的(标准库)特化。我们不能一致地模仿语义。

我认为很明显将三个不同的成员视为数组元素是行不通的,因为指向它们的指针算法受到极大限制(例如,加1会产生pointer past-the-end)。 / p>

因此,我们假设vec3包含三个int的数组。 即使这样,你隐含需要的基础reinterpret_cast<int*>(&v)vvec3)也不会给你留下指向第一个元素的指针。请参阅pointer-interconvertibility上的详尽要求:

  

如果出现以下情况,则ab两个对象指针可互换

     
      
  • 它们是同一个对象,或

  •   
  • 一个是标准布局联合对象,另一个是该对象的非静态数据成员([class.union]),或

  •   
  • 一个是标准布局类对象,另一个是该对象的第一个非静态数据成员,或者,如果该对象没有   非静态数据成员,该对象的第一个基类子对象   ([class.mem]),或

  •   
  • 存在一个对象cac是指针可互换的,cb是   指针的互变的。

  •   
     

如果两个对象是指针可互换的,那么它们具有相同的   地址,并且可以从指针获得指向一个的指针   通过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与此相关。