至于我可以告诉下面的功能不是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?

查看:151
本文介绍了至于我可以告诉下面的功能不是constexpr,但代码编译在clang和g ++。我缺少什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在N4140的§5.19/ 2中有这个例子:

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

据我所知,这不是一个 constexpr 函数。但是代码片段在clang和g ++中编译。请参见实例

$ c $ b

解决方案

在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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆