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

标签 c++ c++17 language-lawyer constexpr c++20

考虑以下示例( 代码段 (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();
      |


live example on godbolt.org

错误类型是有道理的,如 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) ?
  • 所有编译器都正确接受 片段 (1) ?如果是这样,为什么引用是重要的?
  • g++ 9.xg++ trunk正确接受 片段(2) ?
  • 最佳答案

    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 表达式命名引用,该引用没有先前的常量表达式初始化或在常量表达式评估期间开始其生命周期。 [expr.const]/2.11 ( same in C++20 )

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

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



    否,因为表达式仍包含子表达式 x这违反了上述规则。

    关于c++ - 通过引用调用 `constexpr` 成员函数 - clang vs gcc,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60454862/

    相关文章:

    android - 无法使用 Android Studio 和 ndkBuild 在 C++ 中到达断点

    c++ - 在 C++ 中使用 std::set 的最长递增子序列

    C++ “+”(加号)在类实例前面

    c++ - 函数参数 : intedeterminately sequenced or unsequenced?

    c++ - 为什么遍历 unordered_map 但不能更改其映射值?

    c++ - C1202 : recursive type or function dependency context too complex

    c++ - 并行 STL 是否处理插入迭代器,例如 std::back_insert_iterator?

    c++ - 将非算术类型作为参数传递给 cmath 函数是否有效?

    c++ - 使用转换函数直接初始化

    c++ - 默认字符串参数