Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 519
Claudius Avatar asked Jul 10 '19 08:07

Claudius


1 Answers

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

like image 56
user7860670 Avatar answered Oct 27 '22 05:10

user7860670