C++11 将固定数组大小的指针/引用转换为较小的大小是否合法 < P> >根据C++标准,将指针或引用转换为固定数组(例如,代码> T(*)[n] < /代码>或 t(&)[n] < /代码>,以合法地将指针或引用转换为指针或引用相同类型和CV资格的较小固定数组(例如:代码> T(*)[M] < /代码>或 t(&)[M] < /代码>)
基本上,这对于C++11 将固定数组大小的指针/引用转换为较小的大小是否合法 < P> >根据C++标准,将指针或引用转换为固定数组(例如,代码> T(*)[n] < /代码>或 t(&)[n] < /代码>,以合法地将指针或引用转换为指针或引用相同类型和CV资格的较小固定数组(例如:代码> T(*)[M] < /代码>或 t(&)[M] < /代码>),c++11,c++,language-lawyer,C++11,C++,Language Lawyer,基本上,这对于T的所有实例化来说都是格式良好的(无论布局类型如何): void消耗(T(&array)[2]); 无效接收(T和数组)[6]) { 消耗(重新解释施法(数组)); } 我看不到以下任何引用是有效的转换: , , ,甚至 然而,似乎所有主要的编译器都接受这一点,即使在使用T=std::string()时进行了优化,也能生成正确的代码(如果这是未定义的行为,这证明不了多少) 我的理解是,根据类型系统,这应该是非法的,因为T[2]的对象从未真正创建过,这意味着T(&)[2]的引
T
的所有实例化来说都是格式良好的(无论布局类型如何):
void消耗(T(&array)[2]);
无效接收(T和数组)[6])
{
消耗(重新解释施法(数组));
}
我看不到以下任何引用是有效的转换:
- ,
- ,
- ,甚至
T=std::string
()时进行了优化,也能生成正确的代码(如果这是未定义的行为,这证明不了多少)
我的理解是,根据类型系统,这应该是非法的,因为T[2]
的对象从未真正创建过,这意味着T(&)[2]
的引用将无效
我之所以给这个问题加上标签,是因为这是我对答案最感兴趣的版本,但我很想知道这个答案在新版本中是否有所不同。在任何语言版本中,除了没有,这里没有什么要说的:类型完全不相关。C++20确实允许从
T(*)[N]
转换到T(*)[]
(对于引用也是如此),但这并不意味着您可以等效地处理两个不同的N
。最接近此规则的“引用”是[conv.array]/1(“结果是指向数组的第一个元素的指针。”,它在您的示例中不存在T[2]
)和[defns.undefined]中的注释(“当本文档省略任何显式的行为定义时,可能会出现未定义的行为”)
编译器不会“捕获”您的部分原因是这样的
reinterpret\u cast
s可以有效地在一个对象的真实类型上返回,而另一个reinterpret\u cast
用于“偷偷”通过一个需要指向不同类型的指针或引用的接口(但不要将其用作该类型!)这意味着给定的代码是合法的,但是consume
和receive
的调用方的明显定义将一起导致未定义的行为。(另一方面,优化器通常会忽略始终未定义的代码,除非它可以消除分支。)一个迟来的补充答案,它相当于一条评论的质量,但远远超过了允许的内容量:
首先:好问题!值得注意的是,这样一个非常明显的问题很难被验证,甚至在专家中也会产生很多混乱。值得一提的是,我已经经常看到这类代码了
先说说未定义的行为
我认为至少关于指针用法的问题是一个很好的例子,我们必须承认,语言的一个方面的理论上未定义的行为有时会被其他两个方面“击败”: