通过引用调用`constexpr`成员函数-clang vs gcc

Invoking `constexpr` member function through reference - clang vs gcc

考虑以下示例(代码段 (0)):

struct X
{
    constexpr int get() const { return 0; }
};

void foo(const X& x)
{
    constexpr int i = x.get();
}

int main()
{
    foo(X{});
}

以上示例使用 g++ 10.x 之前的所有 g++ 版本进行编译,并且从未在 clang++ 下编译。错误信息是:

error: 'x' is not a constant expression
    8 |     constexpr int i = x.get();
      |

live example on godbolt.org

这种错误是有道理的,因为 x 从来都不是 foo 正文中的常量表达式,但是:


当我将 X::get() 标记为 static(on godbolt.org) 片段 (2) 时,它变得更加有趣。通过该更改,所有测试版本的 g++(包括主干)都可以编译,而 clang++ 仍然总是无法编译。

所以,我的问题:

Is g++ 9.x correct in accepting snippet (0)?

没有

Are all compilers correct in accepting snippet (1)? If so, why is the reference significant?

是的,他们是。

常量表达式不能使用 id-expression 命名没有先前常量表达式初始化或在常量表达式评估期间开始其生命周期的引用。 [expr.const]/2.11 (same in C++20)

如果您在不涉及任何左值到右值转换的情况下命名非引用变量,则情况并非如此。 x.get() 仅将 x 引用为左值,并且仅调用实际上不访问 x 的任何成员的 constexpr 函数,因此没有问题。

Are g++ 9.x and g++ trunk correct in accepting snippet (2)?

否,因为表达式中仍然包含违反上述规则的子表达式x