C++ `标准::复杂<;T>;[n] `and`T[n*2]`类型别名

C++ `标准::复杂<;T>;[n] `and`T[n*2]`类型别名,c++,language-lawyer,strict-aliasing,type-punning,C++,Language Lawyer,Strict Aliasing,Type Punning,因为C++11std::complex[n]保证可别名为T[n*2],具有定义良好的值。这正是人们对任何主流架构的期望。这个保证是用标准C++实现的,对于我自己的类型来说,比如“代码>结构VEC3 {浮点X,Y,Z,} /CODE>,还是只有编译器的特殊支持才可能?”/P> < P>这是唯一可能的,特别是编译器的特别支持。 联合无法实现这一点,因为通用方法实际上具有未定义的行为,尽管与布局兼容的初始序列也有例外,并且作为特例,您可以通过无符号字符*检查对象。不过,就是这样 有趣的是,除非我们假设

因为C++11
std::complex[n]
保证可别名为
T[n*2]
,具有定义良好的值。这正是人们对任何主流架构的期望。这个保证是用标准C++实现的,对于我自己的类型来说,比如“代码>结构VEC3 {浮点X,Y,Z,} /CODE>,还是只有编译器的特殊支持才可能?”/P> < P>这是唯一可能的,特别是编译器的特别支持。 联合无法实现这一点,因为通用方法实际上具有未定义的行为,尽管与布局兼容的初始序列也有例外,并且作为特例,您可以通过
无符号字符*
检查对象。不过,就是这样

有趣的是,除非我们假设“以下”具有广泛而无用的含义,否则该标准在这方面在技术上是矛盾的:

[C++14:5.2.10/1]:
[..]下面列出了可以使用reinterpret\u cast显式执行的转换。不能使用reinterpret_cast显式执行其他转换


然后不再提及复杂的情况。最后,您所指的规则在很久以后的
[C++14:26.4/4]
中介绍,我认为如果您的类型包含
float x[3]
,并且您确保
sizeof(vec3)==3*sizeof(float)&&is\u标准布局
,那么它将适用于单个
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]);
struct vec3{float x[3];}v={};
float*x=重新解释投射(&v);//指向第一个浮点数
断言(x==v.x);
断言(&x[0]==&v.x[0]);
断言(&x[1]==&v.x[1]);
断言(&x[2]==&v.x[2]);

您不能将
vec3
数组视为三倍长度的浮点数组。每个
vec3
中的数组上的数组算法将不允许您访问下一个
vec3
中的数组。与此相关。

TL;DR:编译器必须检查
重新解释cast
s,并找出涉及
std::complex
的(标准库)专门化。我们不能完全模仿语义

我认为很明显,将三个不同的成员视为数组元素是行不通的,因为指向它们的指针上的指针算法受到极大的限制(例如,添加1会产生一个数组)

因此,我们假设
vec3
包含一个由三个
int
s组成的数组。 即使如此,您隐式需要的底层
重新解释\u cast(&v)
(其中
v
vec3
)也不会给您留下指向第一个元素的指针。请参见以下详细要求:

两个对象
a
b
是指针可相互转换的,如果:

  • 它们是相同的对象,或者

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

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

  • 存在一个对象
    c
    ,使得
    a
    c
    是指针可相互转换的,而
    c
    b
    是指针可相互转换的 指针可相互转换

如果两个对象是指针可相互转换的,则它们具有相同的指针 地址,并且可以从指针获取指向某个地址的指针 通过
重新解读
,发送到另一方。[ 注意:数组对象 它的第一个元素不是指针可交换的,即使 他们有相同的地址。 — 尾注 ]

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


最后,即使您成功地获得了指向成员数组第一个元素的指针,如果您有一个
vec3
s数组,您也不能使用简单的指针增量遍历所有成员数组,因为我们得到的指针超过了数组之间的末端e指针与“不共享任何存储”关联(有关详细信息,请参阅).

这完全违背了目标,不是吗?我认为这不能保证有效;请看我的答案。对于标准库类型的类型别名,我们有一个特殊的语言例外?每天学习一些新的东西。不确定这是否矛盾。您引用的条款明确允许转换,但没有给出我们想要的含义t(这就是26.4所做的)。@Columbo:但它“清楚”了吗?IRTA转换[可以说]没有“列在下面”,因此无法显式执行。这就像他们在26.4/4中添加了一个新规则,但忘记了更新5.2.10。什么转换?一个对象左值到另一个对象类型的左值引用的转换?这不是像第11段吗?
launder
有什么帮助?还有,为什么数组不能与其第一个元素相互转换?(这些内容可能过于宽泛,无法发表评论…)@Barry后者可能受到优化的启发。关于前者,您是对的,我忘记检查结构是否已打包。我认为在您的替代解决方案中,第二个
流槽
存在问题。第一个
流槽
确实会给您一个指向
vecarr[0]的指针.a
,但该
int
对象不是数组元素,因此
p+1
不指向
vecarr[0]。b
,它是指向
vecarr[0]末尾的指针。a