在C ++ 14 Standard中,它表示非constexpr函数不能用于constexpr函数的定义吗?

时间:2015-12-14 17:17:50

标签: c++ language-lawyer c++14 constexpr

例如,除非声明<http use-expressions="false"> <intercept-url pattern="/**" access="ROLE_USER" /> <http-basic /> </http> incr(),否则下面的代码无法编译:

constexpr

看看C ++ 14中的§7.1.5/ 3,我们有:

  

constexpr函数的定义应满足以下条件   限制:
  (3.1) - 它不应是虚拟的(10.3);
  (3.2) - 其返回类型应为字面类型;
  (3.3) - 每个参数类型应为文字类型;
  (3.4) - 其函数体应为= delete,= default或不包含

的复合语句      

(3.4.1) - asm-definition,
  (3.4.2) - 转到声明,
  (3.4.3) - 试块或者
  (3.4.4) - 变量的定义   非文字类型或静态或线程存储持续时间或为其   没有执行初始化。

3 个答案:

答案 0 :(得分:11)

后两段,在[dcl.constexpr] / 5:

  

对于非模板,非默认constexpr函数或非模板,非默认,非继承   constexpr构造函数,如果不存在参数值,则调用函数或构造函数   可以是核心常量表达式的评估子表达式(5.20),或者对于构造函数,可以是常量   某个对象的初始化程序(3.6.2),程序格式不正确;无需诊断。

由于foo()incr()可能是核心常量表达式,因此不存在任何参数,因此程序格式错误(NDR)。

答案 1 :(得分:8)

您正在寻找的是§5.19:

  

条件表达式 e 是核心常量表达式,除非根据抽象机器的规则(1.9)评估 e ,将评估以下表达式之一:

这适用于评估作为constexpr函数调用的表达式。也就是说,如果评估函数,即调用constexpr函数将是一个'核心常量表达式',即根据C ++抽象机器的规则执行函数体,不会做任何禁止的事情在第5.19节中给出的列表中。

列表中的一项是:

  
      
  • 调用constexpr函数以外的函数
  •   

所以要将它应用于您的示例:计算表达式foo()会计算对函数incr()的调用,该函数不是constexpr函数,这意味着表达式foo()不是核心常数表达。

此外,由于上述情况适用于您的函数foo的所有可能调用,因此第7.1.5 / 5节中的规则启动并表示您的示例程序格式错误,无需诊断,甚至如果你从未真正致电foo()

正如Ben Voigt所指出的,constexpr函数可以包含对非consexpr函数的调用,只要该函数的特定评估实际上不评估任何此类函数调用(或者它出现在不需要常量的上下文中)表达)。

5.19中的限制仅适用于实际上最终被评估为表达式评估的一部分的表达式。

例如:

#include <iostream>

int incr(int &n) { return ++n; }

enum E {be_constexpr, not_constexpr};

constexpr int foo(E e = be_constexpr) {
  int n = 0;
  if (e == not_constexpr) { incr(n); }
  return n;
}

int main() {
  constexpr int a = foo(); // foo() is a constant expression
  int b = foo(not_constexpr); // may or may not evaluate `foo(non_constexpr)` at runtime. In practice modern C++ compilers will do compile-time evaluation here even though they aren't required to.
  // constexpr int c = foo(not_constexpr); // Compile error because foo(not_constexpr) is not formally a constant expression, even though modern compilers can evaluate it at compile-time.

  std::cout << a << ' ' << b << '\n';
}

答案 2 :(得分:4)

它没有。

以下是允许的,即使它完全符合您的猜测是禁止的:

int incr(int& n) {
    return ++n;
}

constexpr int foo(bool x) {
    int n = 0;
    if (x) incr(n);
    return n;
}

在他的回答中引用了巴里的规则,你的问题中的代码是不允许的。但在我的变体中,确实存在一组参数(特别是false),foo的调用会导致编译时常量表达式。

请注意,不需要诊断 - 符合标准的编译器也可以允许您的版本进行编译。