我从N4140的§5.19/ 2得到了这个例子:
constexpr int incr(int &n) { return ++n; }
据我所知,这不是一个constexpr
功能.但是代码片段用clang和g ++编译.查看实例.我在这里错过了什么?
在C++ 14中,constexpr函数的规则被放宽了,论文N3597:放宽了对constexpr函数的约束.本文介绍了理论基础和效果,其中包括以下内容(强调我的):
与在C++ 11中一样,constexpr关键字用于标记在翻译期间需要实现的函数,如果它们是从需要常量表达式的上下文中使用的话.constexpr函数允许使用任何有效的C++代码,包括局部变量的创建和修改,以及几乎所有语句,并且限制是必须可以在常量表达式中使用constexpr函数.常量表达式可能仍然具有评估及其结果的局部副作用.
和:
保留了对constexpr函数的一些语法限制:
asm-declarations是不允许的.
不允许使用try-blocks和function-try-blocks.
具有静态和线程存储持续时间的变量声明有一些限制(见下文).
我们可以在N4140部分7.1.5
[dcl.constexpr]中找到这个内容,其中说:
constexpr函数的定义应满足以下约束:
它不应是虚拟的(10.3);
其返回类型应为字面类型;
每个参数类型都应是文字类型;
它的函数体应为= delete,= default或不包含的复合语句
asm-definition,
一个goto声明,
尝试块,或
非文字类型或静态或线程存储持续时间的变量的定义,或者不执行初始化的定义.
最后一个示例显示了如何incr
在constexpr中使用:
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),程序不正确; 无需诊断.
作为TC给出的修改示例:
constexpr int& as_lvalue(int&& i){ return i; } constexpr int x = incr(as_lvalue(1)) ;
表明,我们确实可以使用incr
核心常量表达式的子表达式,因此它不是错误的.
据我所知,这不是一个
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规则,可以incr
在constexpr上下文中使用,例如:
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, "!");
实例