【发布时间】:2020-06-12 17:50:04
【问题描述】:
考虑以下示例(sn-p (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(); |
这种错误是有道理的,因为x 在foo 的主体中从来都不是常量表达式,但是:
X::get()被标记为constexpr,它不依赖于x的状态;将
const X&更改为const X会使代码与每个编译器(on godbolt.org) 一起编译sn-p (1)。
当我将X::get() 标记为static ((on godbolt.org) sn-p (2)) 时,它变得更加有趣。通过该更改,g++(包括主干)的所有测试版本都可以编译,而clang++ 仍然始终无法编译。
所以,我的问题:
g++ 9.x接受 sn-p (0) 是否正确?是否所有编译器都正确接受 sn-p (1)?如果是,为什么参考意义重大?
g++ 9.x和g++ trunk是否正确接受 sn-p (2)?
【问题讨论】:
-
constexpr 是值的“掩码”,而 const 是您告知它不会更改的变量。不能引用或指出值,但 const 可以。 get() 函数成员在编译时处理。换句话说,它对所有情况都是 0。正如我之前所说,值不能被引用或指向
-
我认为[expr.const]/2.11 在这里适用,而
foo中的x不是常量表达式。甚至还有 an old (informally rejected) bug report on clang 的正确行为(而 GCC 有一个实际的错误)。 -
@Barry nice,在您的文章中,您还提到了相应的GCC bug report(我只能找到被拒绝的clang),它允许gcc 9.x 接受sn-p 0,此后已更正。
标签: c++ c++17 language-lawyer constexpr c++20