我在N4140的§5.19/ 2中得到了这个例子:
constexpr int incr(int &n) {
return ++n;
}
据我所知,这不是constexpr
函数。但是代码片段用clang和g ++编译。见live example。我在这里缺少什么?
答案 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, "!");