至于我可以告诉下面的功能不是constexpr,但代码编译在clang和g ++。我缺少什么? [英] As far as I can tell the function below is not constexpr, but the code compiles in clang and g++. What am I missing?
问题描述
我在N4140的§5.19/ 2中有这个例子:
constexpr int incr(int& n){
return ++ n;
}
据我所知,这不是一个 constexpr
函数。但是代码片段在clang和g ++中编译。请参见实例。
在C ++ 14中,constexpr函数的规则被放宽了, http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3597.html =nofollow> N3597:放松对constexpr函数的约束。该论文纳入了理由和效果,它包括以下(强调我):
C ++ 11,constexpr关键字用于标记在翻译过程中需要实现的函数,如果它们是从需要常量表达式的上下文使用的。在constexpr函数中允许有任何有效的C ++代码,包括局部变量的创建和修改,以及几乎所有的语句,限制是在常量表达式中使用constexpr函数。常量表达式可能仍然存在对评估及其结果局部的副作用。
p>
对constexpr函数的一些句法限制是
保留:
- 不允许使用asm声明。
- 不允许尝试块和函数块。
- 声明具有静态和线程存储持续时间的变量具有一些限制(见下文)。
发现这包括在N4140节 7.1.5
[dcl.constexpr] 中,其中说:
< blockquote>
constexpr函数的定义应满足以下约束:
-
virtual(10.3);
-
其返回类型应为文字类型;
每个参数类型都应为文字类型; -
其函数体应为= delete,= default或不包含
-
一个asm定义,
-
a goto语句,
-
a try-block或
-
非文字类型或静态或线程存储持续时间或对其执行
无初始化。
-
最后一个例子显示了如何在constexpr中使用 incr
:
constexpr int h(int k){
int x = incr(k) // OK:incr(k)不需要是核心
//常量表达式
return x;
}
constexpr int y = h(1); // OK:用值2初始化y
// h(1)是一个核心常量表达式,因为
// k的生命周期在h(1)内开始
并且规则覆盖 k的生命周期在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
一个核心常数表达式的子表达式,因此它不会形成错误。
I got this example from §5.19/2 in N4140:
constexpr int incr(int &n) {
return ++n;
}
As far as I can tell, this is not a constexpr
function. But the snippet compiles in clang and g++. See live example. What am I missing here?
In C++14 the rules for constexpr function were relaxed and the paper N3597: Relaxing constraints on constexpr functions. The paper goes into the rationale and the effects and it includes the following (emphasis mine):
As in C++11, the constexpr keyword is used to mark functions which the implementation is required to evaluate during translation, if they are used from a context where a constant expression is required. Any valid C++ code is permitted in constexpr functions, including the creation and modification of local variables, and almost all statements, with the restriction that it must be possible for a constexpr function to be used from within a constant expression. A constant expression may still have side-effects which are local to the evaluation and its result.
and:
A handful of syntactic restrictions on constexpr functions are retained:
- asm-declarations are not permitted.
- try-blocks and function-try-blocks are not permitted.
- Declarations of variables with static and thread storage duration have some restrictions (see below).
and we can find this covered in N4140 section 7.1.5
[dcl.constexpr] which says:
The definition of a constexpr function shall satisfy the following constraints:
it shall not be virtual (10.3);
its return type shall be a literal type;
each of its parameter types shall be a literal type;
its function-body shall be = delete, = default, or a compound-statement that does not contain
an asm-definition,
a goto statement,
a try-block, or
a definition of a variable of non-literal type or of static or thread storage duration or for which no initialization is performed.
The last example shows how incr
can be used in a 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)
and the rule that covers the lifetime of k begins inside h(1)
is:
- modification of an object (5.17, 5.2.6, 5.3.2) unless it is applied to a non-volatile lvalue of literal type that refers to a non-volatile object whose lifetime began within the evaluation of e;
The wording in 7.1.5
[dcl.constexpr] shows us why incr
is a valid constexpr:
For a non-template, non-defaulted constexpr function or a non-template, non-defaulted, non-inheriting constexpr constructor, if no argument values exist such that an invocation of the function or constructor could be an evaluated subexpression of a core constant expression (5.19), the program is ill-formed; no diagnostic required.
As the modified example given by T.C.:
constexpr int& as_lvalue(int&& i){ return i; }
constexpr int x = incr(as_lvalue(1)) ;
shows, we can indeed use incr
as a subexpression of a core constant expression and therefore it is not ill-formed.
这篇关于至于我可以告诉下面的功能不是constexpr,但代码编译在clang和g ++。我缺少什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!