使用const引用的Constexpr类未编译

Phi*_*ZXX 2 c++ reference constexpr c++17

我有以下示例代码

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;
}
Run Code Online (Sandbox Code Playgroud)

我用cygwin(gcc 8.2)编译

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;
}
Run Code Online (Sandbox Code Playgroud)

使用MSVC 2019,它可以很好地进行编译,但是IntelliSense具有讽刺意味的aop(a, b),其工具提示为“表达式必须具有恒定值”。

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

Bar*_*rry 5

是的,就持续评估而言,该规则是更复杂的规则之一。

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

因此,如果您将要引用的内容更改为具有静态存储期限,则一切正常:

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

constexpr Operation op(a, b); // now ok
Run Code Online (Sandbox Code Playgroud)

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

在任何constexpr变量声明中,初始化的完整表达式应为常量表达式。

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

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

常量表达式可以是一个glvalue芯常量表达式[...],或或prvalue芯常量表达式,其值满足以下约束条件:

  • 如果该值是类类型的对象,则每个引用类型的非静态数据成员都引用一个实体,该实体是常量表达式的允许结果,
  • [...],
  • 如果该值是类或数组类型的对象,则每个子对象都满足该值的这些约束。

如果实体是具有静态存储持续时间的对象,而该对象不是临时对象或者其值满足上述约束的临时对象,或者它是非立即函数,则该实体是常量表达式允许结果

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

Make abstatic赋予它们静态存储期限,这使它们成为常量表达式的允许结果,这使prvalue初始化满足所有要求,从而使声明op有效。


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

  • 您不认为这对于目前正在试图扩大其吸引力的团体开发的通用编程语言来说是荒谬的神秘和深奥吗? (2认同)
  • 我并不是说它没有技术原因,或者说它是“新的”。我是说这是极其神秘和深奥的。人们(不是像你这样的语言律师)不应该对这样的事情感到好奇。因此,这个问题中的一个明显合理且简单的程序需要在 Stack Overflow 上发布才能真正发挥作用。至少,诊断几乎毫无用处。 (2认同)