【问题标题】:Clang claims constexpr member of generic lambda argument is not constexprClang 声称通用 lambda 参数的 constexpr 成员不是 constexpr
【发布时间】:2019-07-10 08:38:34
【问题描述】:

我想编写一个通用 lambda 作为一个变体的访问者。这个变体的成员包含一个 constexpr 成员值,我想在访问者中使用它。例如:

#include <variant>

template<int r>
struct S {
    constexpr static int this_r = r;
};

int f(std::variant<S<0>, S<1>, S<2> > v) {
    return std::visit([](auto const& arg) {
        if constexpr(arg.this_r == 0) { return 42; }
        else { return arg.this_r; }
    }, v);
}

int g() {
    std::variant<S<0>, S<1>, S<2> > x = S<2>();
    return f(x);
}

GCC 很高兴从 version 7.1 开始编译这段代码。另一方面,Clang 抱怨 if constexprarg.this_r == 0 参数不是恒定的,回到 version 4.0.0 但这仍然存在于 current trunk 中。

谁是正确的,我怎样才能避免这个问题(假设一个简单的if 不会削减它,因为两个分支之一是不可实例化的)?

附录:将 arg 作为值而不是 const 左值引用传递,Clang is happy,但不幸的是,这不是我的选择。

【问题讨论】:

  • 我认为 lambda 参数 arg 不是 constexpr 这里。不过我不确定。
  • arg 本身当然不是 constexpr,但它的成员 this_r 是。一旦知道arg 的类型,arg.this_r 应该是 constexpr?
  • @Claudius 否,因为arg.this_r 是非 constexpr 对象的成员访问表达式。 std::remove_cvref_t&lt;decltype(arg)&gt;::this_r 是一个常量表达式,因为它不使用成员访问表达式。
  • 嗯,进一步研究后,可能 Clang 有一个错误。 MSVC、Intel 和 GCC 都同意没关系:godbolt.org/z/0RcsLC
  • @JonathanWakely 我认为这是一个标准错误,我认为它在技术上不正确,但不应该如此。

标签: c++ c++17 variant generic-lambda


【解决方案1】:

由于this_r 是一个静态成员,您可以随时访问它而无需取消引用(非 constexpr)对对象实例的引用,以使 clang 或其他编译器满意:

int f(std::variant<S<0>, S<1>, S<2> > v) {
    return std::visit([](auto const& arg) {
        if constexpr(::std::remove_reference_t<decltype(arg)>::this_r == 0) { return 42; }
        else { return ::std::remove_reference_t<decltype(arg)>::this_r; }
    }, v);
}

online compiler

【讨论】:

  • 它并没有完全赢得漂亮奖,但考虑到@JonathanWakely 的解释,它似乎有效并且有意义。谢谢!
猜你喜欢
  • 2020-06-12
  • 1970-01-01
  • 2016-07-29
  • 1970-01-01
  • 2020-03-10
  • 2016-04-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多