constexpr未定义的行为

时间:2011-09-14 18:27:45

标签: c++ undefined-behavior c++11 language-lawyer

我一直在试验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();
}

2 个答案:

答案 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找到更多详细信息,这些信息也会用于此功能。