据我所知,下面的函数不是constexpr,但是代码用clang和g ++编译。我错过了什么?

时间:2015-12-10 21:03:57

标签: c++ c++14 constexpr

我在N4140的§5.19/ 2中得到了这个例子:

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

据我所知,这不是constexpr函数。但是代码片段用clang和g ++编译。见live example。我在这里缺少什么?

2 个答案:

答案 0 :(得分:9)

在C ++ 14中,constexpr功能的规则被放宽了,论文N3597: Relaxing constraints on constexpr functions。本文介绍了基本原理和效果,其中包括以下内容(强调我的):

  

与在C ++ 11中一样,constexpr关键字用于标记在翻译期间需要实现的函数,如果它们是从需要常量表达式的上下文中使用的话。 constexpr函数允许使用任何有效的C ++代码,包括局部变量的创建和修改,以及几乎所有语句,并且限制条件是必须可以在常量表达式中使用constexpr函数。常量表达式可能仍然存在评估及其结果的局部副作用。

  

对constexpr函数的一些语法限制是   保留:

     
      
  • 不允许使用asm声明。
  •   
  • 不允许使用try-blocks和function-try-blocks。
  •   
  • 具有静态和线程存储持续时间的变量声明有一些限制(见下文)。
  •   

我们可以在N4140部分7.1.5 [dcl.constexpr] 中找到这一点,其中说:

  

constexpr函数的定义应满足以下约束条件:

     
      
  • 它不应是虚拟的(10.3);

  •   
  • 其返回类型应为文字类型;

  •   
  • 其每个参数类型都应为文字类型;

  •   
  • 其函数体应为= delete,= default或不包含的复合语句

         
        
    • asm-definition,

    •   
    • goto语句,

    •   
    • 试用版,或

    •   
    • 非文字类型或静态或线程存储持续时间或其变量的定义   没有进行初始化。

    •   
  •   

最后一个示例显示了如何在constexpr中使用incr

constexpr int h(int k) {
  int x = incr(k); // OK: incr(k) is not required to be a core
                   // constant expression
  return x;
}

constexpr int y = h(1); // OK: initializes y with the value 2
                        // h(1) is a core constant expression because
                        // the lifetime of k begins inside h(1)

以及涵盖the lifetime of k begins inside h(1)的规则是:

  
      
  • 修改对象(5.17,5.2.6,5.3.2),除非它应用于文字类型的非易失性左值   指的是一个非易失性物体,其寿命始于e;
  • 的评估范围内   

7.1.5 [dcl.constexpr] 中的措辞向我们展示了为什么incr是有效的constexpr:

  

对于非模板,非默认的constexpr函数或非模板,非默认的,非继承的   constexpr构造函数,如果不存在参数值,则调用函数或构造函数   可能是核心常量表达式的评估子表达式(5.19),该程序是不正确的;没有   需要诊断。

作为T.C。给出的修改示例:

constexpr int& as_lvalue(int&& i){ return i; }

constexpr int x = incr(as_lvalue(1)) ;

表明,我们确实可以使用incr作为核心常量表达式的子表达式,因此它不会形成错误。

答案 1 :(得分:7)

  

据我所知,这不是constexpr函数。

为什么这么说? §5.19/ 2的例子是:

constexpr int g(int k) {
    constexpr int x = incr(k); // error: incr(k) is not a core constant
                               // expression because lifetime of k
                               // began outside the expression incr(k)
    return x;
}

incr(k)不是核心常量表达式并不意味着incr不能成为constexpr函数。

在C ++ 14的constexpr规则下,可以在constexpr上下文中使用incr,例如:

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

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

除非函数体不可能constexpr(例如,无条件地调用非constexpr函数),否则编译器没有理由在定义时产生错误。

constexpr函数甚至可能包含正文中的路径/分支,这些路径/分支不会是constexpr。只要他们从未在constexpr上下文中使用,您就不会收到错误。 例如:

constexpr int maybe_constexpr(bool choice, const int& a, const int& b) {
    return choice ? a : b;
}

constexpr int a = 0;
int b = 1;
static_assert(maybe_constexpr(true, a, b) == 0, "!");

live example