例如,除非incr()
声明,否则下面的代码不会编译constexpr
:
int incr(int& n) { return ++n; } constexpr int foo() { int n = 0; incr(n); return n; }
看看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) - goto语句,
(3.4.3) - try-block,或
(3.4.4) - 非文字类型的变量的定义或静态或线程存储持续时间或未执行初始化的时间.
Barry.. 11
两段之后,在[dcl.constexpr]/5中:
对于非模板,非默认
constexpr
函数或非模板,非默认,非继承constexpr构造函数,如果不存在参数值,则调用函数或构造函数可以是核心常量表达式的计算子表达式(5.20),或者,对于构造函数,某个对象(3.6.2)的常量初始化程序,该程序是不正确的; 无需诊断.
没有任何参数存在,因此foo()
可能是核心常量表达式incr()
,因此程序是不正确的(NDR).
两段之后,在[dcl.constexpr]/5中:
对于非模板,非默认
constexpr
函数或非模板,非默认,非继承constexpr构造函数,如果不存在参数值,则调用函数或构造函数可以是核心常量表达式的计算子表达式(5.20),或者,对于构造函数,某个对象(3.6.2)的常量初始化程序,该程序是不正确的; 无需诊断.
没有任何参数存在,因此foo()
可能是核心常量表达式incr()
,因此程序是不正确的(NDR).
你要找的是§5.19:
甲条件表达式 Ë是芯常量表达式除非的评价Ë,以下抽象机(1.9),将评估下面的表达式中的一个的规则:
这适用于作为constexpr
函数调用的表达式的求值.也就是说,constexpr
如果评估函数,即根据C++抽象机器的规则执行函数体,调用函数将是一个'核心常量表达式',不执行在列表中给出的任何禁止的内容§5.19.
列表中的一项是:
调用constexpr函数以外的函数
因此,要将此应用于您的示例:foo()
计算表达式会计算对函数的调用,该函数incr()
不是constexpr函数,这意味着表达式foo()
不是核心常量表达式.
此外,由于上述情况适用于所有可能的函数调用foo
,因此第7.1.5/5节中的规则启动并表示您的示例程序格式错误,无需诊断,即使您从未实际调用过foo()
.
正如Ben Voigt所指出的,constexpr函数可以包含对非consexpr函数的调用,只要该函数的特定评估实际上不评估任何此类函数调用(或者它出现在不需要常量表达式的上下文中).
5.19中的限制仅适用于实际上最终被评估为表达式评估的一部分的表达式.
例如:
#includeint 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'; }