通过引用调用`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(); |
这种错误是有道理的,因为x
从来不是foo
主体中的常量表达式,
-
X::get()
被标记为constexpr
,它不依赖于x
的状态; </p> -
将
const X&
更改为const X
可使代码与每个编译器一起编译 (在godbolt.org上) 摘要(1).
当我将X::get()
标记为static
时,它变得更加有趣( (在godbolt上.org) 摘要(2)).进行此更改后,所有g++
(包括主干)的受测试版本都可以编译,而clang++
仍然始终无法编译.
所以,我的问题:
-
g++ 9.x
接受代码段(0)是否正确? -
所有编译器在接受代码段(1)时是否正确?如果是这样,为什么引用很重要?
-
g++ 9.x
和g++ trunk
接受代码段(2)是否正确?
g ++ 9.x在接受代码段(0)时是否正确?
否.
所有编译器在接受代码段(1)时是否正确?如果是这样,为什么引用很重要?
是的.
常量表达式不能使用id表达式来命名引用,该引用没有先前的常量表达式初始化或在常量表达式求值期间开始其生存期. [expr.const]/2.11 (live example on godbolt.org
The error kind of makes sense, as x
is never a constant expression in the body of foo
, however:
X::get()
is markedconstexpr
and it does not depend on the state ofx
;Changing
const X&
toconst X
makes the code compile with every compiler (on godbolt.org) snippet (1).
It gets even more interesting when I mark X::get()
as static
((on godbolt.org) snippet (2)). With that change, all tested versions of g++
(including trunk) compile, while clang++
still always fail to compile.
So, my questions:
Is
g++ 9.x
correct in accepting snippet (0)?Are all compilers correct in accepting snippet (1)? If so, why is the reference significant?
Are
g++ 9.x
andg++ trunk
correct in accepting snippet (2)?
Is g++ 9.x correct in accepting snippet (0)?
No.
Are all compilers correct in accepting snippet (1)? If so, why is the reference significant?
Yes, they are.
A constant expression cannot use an id-expression naming a reference that doesn't have a previous constant expression initialization or began its lifetime during the constant expression evaluation. [expr.const]/2.11 (same in C++20)
The same is not true if you are naming a non-reference variable without involving any lvalue-to-rvalue conversion. x.get()
only refers to x
as lvalue and only calls a constexpr
function that doesn't actually access any member of x
, so there is no issue.
Are g++ 9.x and g++ trunk correct in accepting snippet (2)?
No, because the expression still contains the subexpression x
which violates the rule mentioned above.
这篇关于通过引用调用`constexpr`成员函数-clang vs gcc的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!