通过引用调用`constexpr`成员函数-clang vs gcc [英] Invoking `constexpr` member function through reference - clang vs gcc

查看:127
本文介绍了通过引用调用`constexpr`成员函数-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();
      |

godbolt.org上的实时示例

这种错误是有道理的,因为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.xg++ 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 marked constexpr and it does not depend on the state of x;

  • Changing const X& to const 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 and g++ 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆