Hum*_*ler 23 c++ language-lawyer c++11
根据 C++ 标准,将指向固定数组(例如T(*)[N]或T(&)[N])的指针或引用转换为指向相同类型和 CV 限定(例如T(*)[M]或T(&)[M])的较小固定数组的指针或引用是否合法?
基本上,对于T(无论布局类型)的所有实例化,这是否总是格式良好的:
void consume(T(&array)[2]);
void receive(T(&array)[6])
{
consume(reinterpret_cast<T(&)[2]>(array));
}
Run Code Online (Sandbox Code Playgroud)
我没有看到任何对这是有效转换的引用:
然而,似乎所有主要编译器都接受这一点并生成正确的代码,即使在使用T = std::string( compiler explorer)时进行了优化(如果它是未定义的行为,这证明不是很多)。
我的理解是,根据类型系统,这应该是非法的,因为T[2]从未真正创建过对象,这意味着对的引用T(&)[2]将是无效的。
我将这个问题标记为c++11,因为这是我对答案最感兴趣的版本,但我很想知道这个答案在较新版本中是否有所不同。
除了no,在任何语言版本中,这里没什么好说的:类型根本不相关。C++20 确实允许从T (*)[N]to转换T (*)[](对于引用也是如此),但这并不意味着您可以N等效地对待两个不同的s。最接近此规则的“引用”是 [conv.array]/1(“结果是指向数组第一个元素的指针。”,T[2]在您的示例中不存在)和[defns.undefined] 中的注释(“当本文档省略任何明确的行为定义时,可能会出现未定义的行为”)。
编译器没有“抓住”你的部分原因是这样的reinterpret_casts可以有效地返回到一个对象的真实类型,然后另一个reinterpret_cast用于通过一个需要指针或对不同类型的引用的接口“偷偷摸摸”它(但不使用它作为那种类型!)。这意味着给定的代码是合法的,但是明显的 forconsume和 caller for定义receive会一起导致未定义的行为。(另一部分是优化器通常会单独留下始终未定义的代码,除非它可以消除分支。)