编译器是否被迫拒绝无效的constexpr?

Phi*_*ßen 9 c++ language-lawyer constexpr c++11

#include <exception>

constexpr bool foo(bool x)
{
  return x ? true : throw std::exception();
}

int main()
{
  // 1) must never be compiled
  // static_assert(foo(false), "");

  // 2) must always be compiled?
  const bool x = foo(false);

  // 3) must never compile?
  constexpr bool y = foo(false);

  return 0;
}
Run Code Online (Sandbox Code Playgroud)

我确信(1)必须导致编译错误.我很确定(2)在编译时不能被拒绝,尽管它会在运行时失败.

有趣的案例是constexpr变量(3).在这个简单的例子中,gcc和clang实际上会计算表达式,因此会拒绝该程序.(错误消息:y不是常量表达式).

每个C++ 11编译器都被迫拒绝该程序吗?如果foo(false)被更复杂的表达式替换怎么办?

我很惊讶地发现constexpr没有图灵完整,虽然它将在规范发生变化之后: 基于constexpr的计算Turing是否完整?

也许这与我的问题有关.据我所知,允许编译器推迟在本例中对constexpr(3)的实际评估,直到运行时.但是如果constexpr是turing-complete,我发现很难相信编译器可以决定是否所有constexpr都会抛出异常(这意味着constexpr无效).

asc*_*ler 8

通过我的阅读,是的,每个编译器都必须抱怨声明(3).

N3242 7.1.5第9段:

constexpr对象声明中使用的说明符将对象声明为const.这样的对象应具有文字类型并应初始化.如果它是通过构造函数调用初始化的,那么该调用应该是一个常量表达式(5.19).否则,其初始化程序中出现的每个完整表达式都应是一个常量表达式.用于转换初始化表达式和用于初始化的每个构造函数调用的每个隐式转换都应该是常量表达式中允许的转换之一(5.19).

我认为constexpr对象是"在编译时评估",而constexpr函数或constexpr构造函数是"可能在编译时评估".编译器必须在编译时确定语句(如(3))的语义有效性.您可能会认为"评估"仍然可以在运行时完成,但无论如何,检查有效性的大部分工作都是如此.此外,代码可以继续实例化模板Check<y>,这几乎可以保证编译器需要y在编译时计算出值.

这意味着你可以编写一个恶魔般的程序来使编译器花费很长时间或无限时间.但我怀疑这已经成为可能了operator->.


Xeo*_*Xeo 5

我确信(1)必须导致编译错误.我很确定(2)在编译时不能被拒绝,尽管它会在运行时失败.

正确.throw条件运算符的一部分不是常量表达式,在(1)中,它不是未评估的.对于(2),foo不强制在编译时进行评估.

对于(3),如何允许编译器进行后评估?该constexprDECL说明符的力量 foo在编译时进行评估.它与(1)基本相同,初始化y需要常量表达式的上下文.

§7.1.6 [dcl.constexpr] p9

constexpr对象声明中使用的说明符将对象声明为const.这样的对象应具有文字类型并应初始化.如果它是由构造函数调用初始化的,那么该调用应该是一个常量表达式(5.19).否则,或者如果constexpr在引用声明中使用了说明符,则其初始值设定项中出现的每个完整表达式都应是常量表达式.[...]