是一个编译器被迫拒绝无效constexpr?(Is a compiler forced to rej

2019-08-02 01:16发布

#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;
}

我敢肯定,(1)必须导致编译错误。 我很肯定(2)不得在编译时被拒绝,但它会在运行时失败。

有趣的情况是constexpr变量(3)。 在这个简单的例子,gcc和铛实际计算表达式,并且因此将拒绝该程序。 (错误消息:y不是一个常量表达式)。

是每一个C ++编译器11被迫拒绝该计划? 如果什么FOO(假)是由一个更复杂的表达式替换?

我很惊讶地发现,constexpr没有图灵完备的,但它会在规格变更后: 是基于constexpr-计算图灵完备?

也许这是有关我的问题。 据我了解,编译器被允许在这个例子推迟constexpr(3)的实际评测,直到运行时。 但是,如果constexpr是图灵完备的,我觉得很难相信,编译器可以为所有决定constexpr的异常是否会被抛出(这意味着constexpr是无效的)。

Answer 1:

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

N3242 7.1.5条第9款:

constexpr在对象声明中使用指定符的对象作为const 。 这样的对象应具有文本类型,并应被初始化。 如果通过一个构造呼叫初始化,即呼叫应是常量表达式(5.19)。 否则,出现在它的初始化每满表达应是常量表达式。 在转换初始化表达式和用于初始化每个构造呼叫中使用的每个隐式转换应是允许的常量表达式(5.19)中的一个。

我想的constexpr对象为“在编译时评估”,和constexpr功能或constexpr构造为“可能在编译时进行评估”。 编译器必须确定像(3)在编译时语句的语义有效性。 你可以争辩说,“评价”仍然可以在运行时完成,但检查的有效性负责大部分工作的反正。 此外,该代码可以再继续像实例化一个模板Check<y>这几乎保证了编译器需要弄清楚的价值y在编译时。

这是否意味着你可以写一个恶魔般的程序,以使编译器需要一个很长的或无限的时间。 但我怀疑,已经可能与operator->技巧。



Answer 2:

我敢肯定,(1)必须导致编译错误。 我很肯定(2)不得在编译时被拒绝,但它会在运行时失败。

正确。 该throw条件运算符的部分不是常量表达式,和(1)中,它不是未计算的。 对于(2), foo不会被迫在编译时进行评估。

对于(3),如何将编译器被允许推迟实施后评价? 该constexpr DECL说明符 foo在编译时进行评估。 这是基本相同的(1)中,初始化y是在需要的常量表达式的上下文。

§7.1.6 [dcl.constexpr] p9

constexpr在对象声明中使用指定符的对象作为const 。 这样的对象应具有文本类型,并应被初始化。 如果它是由一个构造函数调用初始化,即呼叫应是常量表达式(5.19)。 否则 ,或者如果constexpr说明符以引用声明使用的, 出现在它的初始值设定每全表达应是常量表达式。 [...]



文章来源: Is a compiler forced to reject invalid constexpr?