Clang утверждает, что constexpr член общего аргумента лямбда не является constexpr - PullRequest
6 голосов
/ 10 июля 2019

Я хотел бы написать общую лямбду в качестве посетителя для варианта. Члены этого варианта содержат значение члена 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 , но он все еще присутствует в текущей магистрали .

Кто здесь справа и как я мог избежать этой проблемы (при условии, что простой if не обрезает ее, потому что одна из двух ветвей не является экземпляром)?

Приложение: передавая arg в качестве значения вместо ссылки на постоянное значение, Clang счастлив , но, к сожалению, это не вариант для меня.

1 Ответ

7 голосов
/ 10 июля 2019

Поскольку 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);
}

онлайн-компилятор

...