请考虑以下示例(片段(0)):
struct X
{
constexpr int get() const { return 0; }
};
void foo(const X& x)
{
constexpr int i = x.get();
}
int main()
{
foo(X{});
}
上面的示例使用g++
之前的所有g++ 10.x
版本进行编译,而从未在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) 代码段(1)。
当我将X::get()
标记为static
((on godbolt.org) 片段(2))时,它变得更加有趣。进行此更改后,g++
的所有测试版本(包括主干)都将编译,而clang++
仍然始终无法编译。
所以,我的问题:
g++ 9.x
接受代码段(0)正确吗?
所有编译器是否都正确接受snippet(1)?如果是这样,为什么引用很重要?
g++ 9.x
和g++ trunk
接受代码段(2)正确吗?
Gcc 9.x在这里是错误的。
使用constexpr int i = x.get();
,您需要在编译时确定i的值。
但是x是运行时参数-您可以在运行时使用任何参数调用foo;因此,在编译时可能无法知道x.get()
返回的值。因此,在编译时不可能知道i的值。