Claudius
Claudius

Reputation: 560

Clang claims constexpr member of generic lambda argument is not constexpr

I would like to write a generic lambda as a visitor for a variant. The members of this variant contain a constexpr member value, which I would like to use in the visitor. For example:

#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 is happy to compile this code starting from about version 7.1. Clang, on the other hand, complains that the arg.this_r == 0 argument to the if constexpr is not constant, going back to version 4.0.0 but this is still present in the current trunk.

Who is in the right here and how could I avoid this issue (assuming that a simple if does not cut it because one of the two branches is not instantiable)?

Addendum: Passing arg as a value instead of a const lvalue reference, Clang is happy, but unfortunately this is not an option for me.

Upvotes: 6

Views: 122

Answers (1)

user7860670
user7860670

Reputation: 37487

Since this_r is a static member you can always access it without dereferencing (non constexpr) reference to object instance to make clang or other compilers happy:

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

Upvotes: 7

Related Questions