首页 > 解决方案 > Clang 声称通用 lambda 参数的 constexpr 成员不是 constexpr

问题描述

我想写一个通用的 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 很高兴从7.1 版开始编译此代码。另一方面,Clang 抱怨arg.this_r == 0参数if constexpr不是恒定的,回到版本 4.0.0但这仍然存在于当前的 trunk中。

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

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

标签: c++c++17variantgeneric-lambda

解决方案


由于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);
}

在线编译器


推荐阅读