我一直在用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();
}
发布于 2011-09-15 07:59:09
§5.19/2 (在第二页;它确实应该分成许多段落)禁止包含以下内容的常量表达式
-左值到右值的转换(4.1),除非将其应用于
-整型或枚举型的glvalue,引用具有先前初始化、使用常量表达式初始化的非易失性常量对象,或
-文本类型的GL值,它引用了用constexpr定义的非易失性对象,或者引用了这样的对象的子对象
与边界数组访问不同,str[1000]
转换为* ( str + 1000 )
,它不引用str
的子对象。因此,这是一个可诊断的规则,编译器需要发出错误。
编辑:关于这个诊断是如何产生的,似乎有一些困惑。当表达式需要为常量时,编译器根据§5.19检查该表达式。如果表达式不满足要求,编译器就会被要求报错。实际上,需要针对任何可能导致未定义行为的常量表达式进行验证。*这可能涉及也可能不涉及尝试计算表达式。
*在C++11中,“一个没有数学定义的结果”。在C++14中,根据定义(§1.3.24),“具有未定义行为的操作”忽略了实现可能定义为回退的行为。
发布于 2014-01-24 05:23:02
是的,编译器应该在编译时捕捉到这一点,如果我们查看draft C++ standard的5.19
常量表达式部分第2段,它会将其列为常量表达式的排除项:
-一种具有未定义行为的操作注:包括,例如,带符号整数溢出(第5条)、某些指针算术(5.7)、除零(5.6)或某些移位操作(5.8) -end注释;
据我所知,issue 695说未定义的行为是非常量,应该发出诊断:
CWG的共识是,像1/0这样的表达式应该简单地被认为是非常量;任何诊断都将导致在需要常量表达式的上下文中使用该表达式。
你可以在我的self answered question here上找到更多细节,它也介绍了这个功能的用法。
https://stackoverflow.com/questions/7421170
复制相似问题