【问题标题】:Why does std::reverse used in consteval function does compile though not constexpr为什么在 consteval 函数中使用的 std::reverse 确实编译虽然不是 constexpr
【发布时间】:2021-01-20 16:50:42
【问题描述】:

在 CompilerExplorer 上使用这个小代码 sn-p 和 std=c++20 for x86-64 clang 11.0.0 编译并运行。

#include <algorithm>
#include <array>

consteval std::array<double,2> gof()
{
    std::array<double,2> x{ 3., 2.};
    std::reverse(begin(x),end(x));
    return x;
}

int
main(int argc, char *argv[])
{
    return gof().at(0);
}

但是在具有相同设置的 CompilerExplorer 上的 clang-tidy 会产生

clang-tidy (trunk) #1 with x86-64 clang 11.0.0

<source>:14:12: error: call to consteval function 'gof' is not a constant expression [clang-diagnostic-error]
    return gof().at(0);
           ^
<source>:7:5: note: non-constexpr function 'reverse<double *>' cannot be used in a constant expression
    std::reverse(begin(x),end(x));
    ^
<source>:14:12: note: in call to 'gof()'
    return gof().at(0);
           ^
/opt/compiler-explorer/gcc-9.2.0/lib/gcc/x86_64-linux-gnu/9.2.0/../../../../include/c++/9.2.0/bits/stl_algo.h:1180:5: note: declared here
    reverse(_BidirectionalIterator __first, _BidirectionalIterator __last)
    ^

clang-tidy 的产出是我所期望的。为什么 clang 处理它的方式不同?

【问题讨论】:

    标签: c++ std clang++ c++20 compiler-explorer


    【解决方案1】:

    std::reverse 在 C++20 中是 constexpr(问题标题暗示其他情况?),所以 gof() 中的任何内容都不会阻止它成为有效的常量表达式。

    libstdc++ 实现了 constexpr 更改,而 libc++ 还没有。因此,如果您使用 libstdc++(就像编译器资源管理器中默认的 clang 一样),它会正常工作。但是如果你使用 libc++ explicitly,那么它会因为你期望的原因而失败(std::reverse 不是 constexpr,这使得 gof() 不能成为一个常量表达式)。 clang-tidy 看起来它使用的是旧版本的 libstdc++(您粘贴的错误为 9.2),这是在 libstdc++ 实施 constexpr 更改之前。

    所以基本上,您只是在此处跨越constexpr 支持的最前沿。

    【讨论】:

    • 理论上我同意。但看看实现,std::reverse 在版本 11.0.0 中不是 constexpr,分别是它附带的 libc++ 版本。标准说应该是这样,但实施还不是那样。
    • @AlexanderStippler 好吧,确实,如果你使用 libc++,then it fails 就是因为这个原因。
    • 那么clang-tidy的问题是libc++?或者你怎么看?
    • @AlexanderStippler 看起来 clang-tidy 使用的是旧版本的 libstdc++(从路径可以看出它是 gcc 9.2)
    猜你喜欢
    • 2020-12-03
    • 1970-01-01
    • 2021-02-20
    • 1970-01-01
    • 1970-01-01
    • 2020-08-29
    • 1970-01-01
    • 2020-10-30
    • 1970-01-01
    相关资源
    最近更新 更多