我一直在试验constexpr
。在我的测试编译器(g ++ 4.6)上,无法编译带有关于越界访问的错误。是否需要编译器 才能在编译时发现它?
#include <iostream>
constexpr const char *str = "hi";
constexpr int fail() {
return str[1000]; // Way past the end!
}
template <int N>
struct foo {
static void print() { std::cout << N << std::endl; }
};
int main() {
foo<fail()>::print();
}
答案 0 :(得分:11)
§5.19/ 2(在第二页;它确实应该分成许多段落)禁止包含
的常量表达式- 左值 - 右值转换(4.1),除非它适用于
- 整数或枚举类型的glvalue,它引用具有先前初始化的非易失性const对象,使用常量表达式初始化,或
- 文字类型的glvalue,引用用constexpr定义的非易失性对象,或引用此类对象的子对象
str[1000]
转换为* ( str + 1000 )
,与str
的子对象不同,与入站数组访问不同。所以这是一个可诊断的规则,编译器需要抱怨。
编辑:对于这种诊断是如何产生的,似乎存在一些混淆。当需要保持不变时,编译器会根据§5.19检查表达式。如果表达式不满足要求,则编译器需要进行投诉。实际上,需要针对可能导致未定义行为的任何事物验证常量表达式。*这可能涉及也可能不涉及尝试评估表达式。
*在C ++ 11中,“未经数学定义的结果”。在C ++ 14中,“一个具有未定义行为的操作”,根据定义(§1.3.24),它忽略了实现可能定义为回退的行为。
答案 1 :(得分:5)
是的,编译器应该在编译时捕获它,如果我们查看5.19
{em> 2 段 2 {{3}它将此列为常量表达式的排除:
据我所知,- 具有未定义行为的操作 [注意:包括,例如,有符号整数溢出(第5条),某些指针算术(5.7),除零(5.6)或某些轮班操作(5.8) - 注意事项];
和draft C++ standard表示未定义的行为是非const ,应该发出诊断信息:
CWG的共识是,像1/0这样的表达应简单地视为非常数;在需要常量表达的上下文中使用表达式会导致任何诊断。
您可以在我的issue 695找到更多详细信息,这些信息也会用于此功能。