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

`std::complex<T>[n]` and `T[n*2]` type aliasing

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

大多数情况下只有编译器的特殊支持才有可能。

联合不会让你到达那里,因为通用方法实际上有未定义的行为,尽管布局兼容的初始序列有例外,并且你可以通过 unsigned char* 检查对象作为特殊情况。仅此而已。

有趣的是,除非我们假设 "below" 具有广泛且无用的含义,否则该标准在这方面在技术上是自相矛盾的:

[C++14: 5.2.10/1]: [..] Conversions that can be performed explicitly using reinterpret_cast are listed below. No other conversion can be performed explicitly using reinterpret_cast.

complex<T> 的情况就不提了。最后,您所指的规则在很久很久以后在 [C++14: 26.4/4].

中引入

我认为如果您的类型包含 float x[3],并且您确保 sizeof(vec3) == 3*sizeof(float) && is_standard_layout_v<vec3>,那么它可以用于单个 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 与此处相关。

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

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

所以我们假设 vec3 包含一个包含三个 int 的数组。 即使这样,您隐式需要的基础 reinterpret_cast<int*>(&v)(其中 vvec3)也不会为您留下指向第一个元素的指针。请参阅 pointer-interconvertibility:

的详尽要求

Two objects a and b are pointer-interconvertible if:

  • they are the same object, or

  • one is a standard-layout union object and the other is a non-static data member of that object ([class.union]), or

  • one is a standard-layout class object and the other is the first non-static data member of that object, or, if the object has no non-static data members, the first base class subobject of that object ([class.mem]), or

  • there exists an object c such that a and c are pointer-interconvertible, and c and b are pointer-interconvertible.

If two objects are pointer-interconvertible, then they have the same address, and it is possible to obtain a pointer to one from a pointer to the other via a reinterpret_­cast. [ Note: An array object and its first element are not pointer-interconvertible, even though they have the same address.  — end note ]

这很明确;虽然我们可以获得指向数组的指针(作为第一个成员),并且指针相互转换是可传递的,但我们无法获得指向其第一个元素的指针。

最后,即使您设法获得了指向成员数组第一个元素的指针,如果您有一个 vec3 的数组,您也无法 遍历 所有成员数组都使用简单的指针增量,因为我们得到的指针超过了数组的末尾。 launder 也没有解决这个问题,因为指针关联的对象不共享任何存储(具体请参见 [ptr.launder])。