使用const引用的Constexpr类未编译 [英] Constexpr Class taking const references not compiling

查看:85
本文介绍了使用const引用的Constexpr类未编译的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下示例代码

template<class T1, class T2>
class Operation
{
public:
    constexpr Operation(const T1& lhs, const T2& rhs) noexcept
        : m_lhs(lhs), m_rhs(rhs) { }

private:
    const T1& m_lhs;
    const T2& m_rhs;
};

int main()
{
    constexpr int a = 3;
    constexpr int b = 4;

    constexpr Operation op(a, b);

    return 0;
}

用cygwin(gcc 8.2)编译得到

Compiling this with cygwin (gcc 8.2) I get

error: 'Operation<int, int>{a, b}' is not a constant expression:
       constexpr Operation op(a, b);

使用MSVC 2019可以很好地编译,但是IntelliSense具有讽刺意味的是强调了 a op(a,b)中的code>,其提示为表达式必须具有恒定值。

With MSVC 2019 it compiles fine, but IntelliSense ironically underlines the a in op(a, b) with the tooltip "expression must have a constant value".

关于此问题是什么以及如何解决的任何建议?

Any advice as to what the issue is, and how to fix it?

推荐答案

是的,此规则是其中一项就常量求值而言,是更复杂的对象。

Yeah, this rule is one of the more complex ones as far as constant evaluation is concerned.

基本上,您不能对没有静态存储持续时间的对象使用constexpr引用。引用对象基本上就是复制其地址-为了使对象的地址成为常量表达式,该地址本身必须是常量-因此必须持久。也就是说,它必须是 static

Basically, you cannot have a constexpr reference to an object that doesn't have static storage duration. Taking a reference to an object is basically copying its address - and in order for an object's address to be a constant expression, the address itself needs to be constant - so it has to persist. That is, it needs to be static.

因此,如果您更改要引用的内容以具有静态存储持续时间, ,一切正常。

So if you change the things you're referring to to have static storage duration instead, everything works:

static constexpr int a = 3;
static constexpr int b = 4;

constexpr Operation op(a, b); // now ok




您的程序所违反的特定规则是 [expr.const] / 10 和TC帮助我了解了它的适用范围。声明 constexpr 变量要求初始化是一个常量表达式( [dcl.constexpr / 10] ):


The specific rule your program violates is [expr.const]/10, and T.C. helped me understand how it applies. Declaring a constexpr variable requires the initialization to be a constant expression ([dcl.constexpr/10]):


在任何constexpr变量声明中,完整-初始化的表达式应该是一个常量表达式。

In any constexpr variable declaration, the full-expression of the initialization shall be a constant expression.

我们没有这么说,但这是有道理的,并且肯定有助于解决这种特殊情况,但是初始化的完整表达指的是初始化的完整表达。可以解释为prvalue,因为prvalue是一个表达式,其求值初始化一个对象( [basic.lval] / 1 )。

We don't say this, but it makes sense and certainly helps resolve this particular situation, but the "full-expression of the initialization" can be interpreted as a prvalue -- since a prvalue is an expression whose evaluation initializes an object ([basic.lval]/1).

现在,[expr.const] / 10读取:

Now, [expr.const]/10 reads:


一个常量表达式是glvalue核心常量表达式[...],或者是其值满足以下约束的prvalue核心常量表达式:

A constant expression is either a glvalue core constant expression [...], or or a prvalue core constant expression whose value satisfies the following constraints:


  • 如果该值是类类型的对象,则每个引用类型的非静态数据成员都引用一个实体,该实体是常量表达式的允许结果,

  • [...],

  • 如果该值是类或数组类型的对象,则每个子对象都满足该值的这些约束。

一个实体是一个常量表达式的允许结果,如果它是一个具有静态存储持续时间的对象,或者它不是一个临时对象,或者是一个其值临时的对象满足

An entity is a permitted result of a constant expression if it is an object with static storage duration that either is not a temporary object or is a temporary object whose value satisfies the above constraints, or if it is a non-immediate function.

初始化 Operation(a,b)是一个prvalue,因此我们需要每个引用数据成员引用一个常量表达式所允许的实体。我们的参考数据成员指的是 a b ,它们都不具有静态存储期限,也不是临时存储,也不是非临时存储。即时功能。因此,整体初始化不是常量表达式,而且格式不正确。

The initialization Operation(a, b) is a prvalue, so we need each reference data member to refer to an entity that is permitted as a result of a constant expression. Our reference data members refer to a and b, neither of which has static storage duration nor are temporaries nor are non-immediate functions. Hence, the overall initialization isn't a constant expression, and is ill-formed.

制作 a b 静态为它们提供了静态存储持续时间,这使它们成为常量表达式的允许结果,这使prvalue初始化满足所有要求,从而使 op 有效。

Making a and b static gives them static storage duration, which makes them permitted results of constant expressions, which makes the prvalue initialization satisfy all the requirements, which makes the declaration of op valid.

这是一条漫长的说法:在进行持续评估时,所有地方都必须始终保持不变下。我们的某些措辞方式非常复杂(像这样),但是它基于以下基本思想:常量评估模型基本上就像是暂停评估代码以运行单独的程序以产生答案。产生 op 要求这些地址是已知的固定的东西-并且仅在静态存储期限内发生。

This is all a long winded way of saying: when dealing with constant evaluation, everything everywhere has to be constant all the way down. Some of our ways of wording this are very complex (like this one), but it's based on the fundamental idea that the model of constant evaluation is basically like pausing evaluating the code to go run a separate program to produce an answer. Producing op requires these addresses to be known, fixed things - and that only happens for static storage duration.

这篇关于使用const引用的Constexpr类未编译的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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