C++ constexpr未定义行为

C++ constexpr未定义行为,c++,undefined-behavior,c++11,language-lawyer,C++,Undefined Behavior,C++11,Language Lawyer,我一直在试验constexpr。在我的测试编译器(g++4.6)上,它无法编译,并出现关于越界访问的错误。编译器需要在编译时发现这一点吗 #包括 constexpr const char*str=“hi”; constexpr int fail(){ return str[1000];//已过终点! } 模板 结构foo{ 静态void print(){std::cout§5.19/2(在第二页;它确实应该被分成许多段落)禁止包含 -左值到右值的转换(4.1),除非应用于 -整型或枚举类型的gl

我一直在试验
constexpr
。在我的测试编译器(g++4.6)上,它无法编译,并出现关于越界访问的错误。编译器需要在编译时发现这一点吗

#包括
constexpr const char*str=“hi”;
constexpr int fail(){
return str[1000];//已过终点!
}
模板
结构foo{
静态void print(){std::cout§5.19/2(在第二页;它确实应该被分成许多段落)禁止包含

-左值到右值的转换(4.1),除非应用于

-整型或枚举类型的glvalue,它引用具有先前初始化、使用常量表达式初始化或

-一种文本类型的glvalue,它引用用constexpr定义的非易失性对象,或引用此类对象的子对象

str[1000]
转换为
*(str+1000)
,它不引用
str
的子对象,与边界内数组访问相反。因此,这是一个可诊断规则,编译器需要投诉

编辑:关于该诊断是如何产生的,似乎存在一些混淆。当需要常量时,编译器将根据§5.19检查表达式。如果表达式不满足要求,编译器将被要求投诉。实际上,它需要根据任何需要验证的常量表达式否则会导致未定义的行为。*这可能涉及也可能不涉及尝试计算表达式


*在C++11中,“未经数学定义的结果”。在C++14中,“具有未定义行为的操作”,根据定义(§1.3.24)忽略实现可能定义为回退的行为。

是的,编译器应该在编译时捕获此行为,如果我们查看第5.19节常量表达式,它的第2段将此列为常量表达式的排除项:

-具有未定义行为的操作[注:包括,例如,有符号整数溢出(第5条)、某些指针算术(5.7)、除零(5.6)或某些移位操作(5.8)-结束注]

据我所知,未定义的行为是非常量的,应该进行诊断:

CWG的共识是,像1/0这样的表达式应该被简单地认为是非常量的;任何诊断都将源于在需要常量表达式的上下文中使用该表达式


您可以在my上找到更多详细信息,其中也介绍了此功能的使用。

编译器必须能够确定
fail()的值
在编译时。因为它不能,所以它会产生一个错误。对我来说听起来很合乎逻辑。@Kerrek-但是如果它是未定义的行为,那么编译器的实现为
N
选择一个随机值或者在链接过程中失败是非常合理的。或者在运行时,甚至在编译时以某种奇怪的方式失败?我看不到任何di我在草稿中的
§5.19[expr.const]
中对此进行了讨论。显然,您不希望编译器(lookout ideone!)中出现缓冲区溢出,但这并不意味着唯一明智的解决方案是错误消息。Re UB:在这种情况下,在编译时已知并违反边界,甚至需要进行一些工作来产生奇怪的行为(至少在不压缩整个编译器的情况下)。我希望其他编译器作者也能理智地产生错误,即使这不是标准所要求的。@Georg-我同意你不想在不做一些事情的情况下发布编译器,并且发现它是如此容易,我怀疑很难反驳它,但我对所有的“经典”感到困惑UB到目前为止,我认为这是唯一一个我看不到明确禁止的问题。这更像是一个学术问题,而不是一个实践问题。这肯定是错误的,但你能证明它是可诊断的吗?
s/diagnosable/required to be diagnostics/
我一方面可以计算出这类需要诊断的事情的数量,还有如果是这样的话,我会感到惊讶。@Tomalak:没有解引用发生,因为表达式首先无法形成。§5.19描述了常量表达式中可以包含的内容。这是不可能的。故事结束。@Omni:
str[1]
是文本类型的glvalue的子对象,该glvalue引用了使用constexpr定义的非易失性对象。
str[1000]
不是。一个是定义良好的,另一个是不允许的。@Omni:没错。除了没有关于找到任何可能导致UB的东西的广泛推论外,它只是5.19的一个特定规则的应用程序。包含UB的常量表达式的一个示例是有符号整数溢出。有人可以合理地预期wraparound,一个编译时错误,或将捕获值编译到程序中并在运行时导致问题。