Неверный явно заданный аргумент для параметра шаблона, который является constexpr - PullRequest
0 голосов
/ 30 декабря 2018

У меня есть static_loop конструкция, подобная этой

template <std::size_t n, typename F> void static_loop(F&& f) {
    static_assert(n <= 8 && "static loop size should <= 8");
    if constexpr (n >= 8)
        f(std::integral_constant<size_t, n - 8>());
    if constexpr (n >= 7)
        f(std::integral_constant<size_t, n - 7>());
    if constexpr (n >= 6)
        f(std::integral_constant<size_t, n - 6>());
    if constexpr (n >= 5)
        f(std::integral_constant<size_t, n - 5>());
    if constexpr (n >= 4)
        f(std::integral_constant<size_t, n - 4>());
    if constexpr (n >= 3)
        f(std::integral_constant<size_t, n - 3>());
    if constexpr (n >= 2)
        f(std::integral_constant<size_t, n - 2>());
    if constexpr (n >= 1)
        f(std::integral_constant<size_t, n - 1>());
}


template <typename T> constexpr size_t tupleSize(T) { return tuple_size_v<T>; }
struct A {
    int a;
    int b;
    void run() {
        auto ab = std::make_tuple(std::ref(a), std::ref(b));
        static_loop<tupleSize(ab)>([&](auto i) { std::get<i>(ab) = i; });
        std::cout << a << " " << b << std::endl;
    }
};

Однако, она не может перебрать кортеж, как указано выше.

пример live godbolt

Ответы [ 2 ]

0 голосов
/ 30 декабря 2018

Измените

template <typename T>
constexpr size_t tupleSize(T) { return tuple_size_v<T>; }

на:

template <typename T>
constexpr size_t tupleSize(T const&) { return tuple_size_v<T>; }

То есть аргумент принимается по ссылке на const, а не по значению.Как есть, вы пытаетесь скопировать кортеж non-constexpr в константном выражении - это не может работать.По ссылке это хорошо, так как вы на самом деле не читаете кортеж.

0 голосов
/ 30 декабря 2018

Предложение: попробуйте с

// .........VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
static_loop<std::tuple_size_v<decltype(ab)>>([&](auto i) { std::get<i>(ab) = i; });

Я имею в виду ... вы не можете использовать ab (в качестве значения) в постоянном выражении, потому что ab не определено constexpr.

И вы не можете определить его constexpr, потому что он инициализирован с использованием std::ref(), который не constexpr.

Но вас не интересует ab как значениеполучить размер своего типа;вас интересует только тип ab;так что вы можете пройти через decltype(ab).

- РЕДАКТИРОВАТЬ -

Не по теме.

Вместо static_loop(), вы можетеиспользуйте классический способ, основанный на std::index_sequence (и сворачивании шаблонов, начиная с C ++ 17).

Я имею в виду ... если вы определите функцию run_1() (с помощником run_1_helper()) какследует

template <typename F, typename ... Ts, std::size_t ... Is>
void run_1_helper (F const & f, std::tuple<Ts...> & t, std::index_sequence<Is...> const)
 { (f(std::get<Is>(t), Is), ...); }

template <typename F, typename ... Ts>
void run_1 (F const & f, std::tuple<Ts...> & t)
 { run_1_helper(f, t, std::index_sequence_for<Ts...>{}); }

Вы можете написать A следующим образом

struct A {
    int a;
    int b;
    void run() {
        auto ab = std::make_tuple(std::ref(a), std::ref(b));
        run_1([](auto & v, auto i){ v = i; }, ab);
        std::cout << a << " " << b << std::endl;
    }
};

Или, может быть, лучше, просто используя std::apply(), как следует

struct A {
    int a;
    int b;
    void run() {
        auto ab = std::make_tuple(std::ref(a), std::ref(b));
        int i { -1 };
        std::apply([&](auto & ... vs){ ((vs = ++i), ...); }, ab);
        std::cout << a << " " << b << std::endl;
    }
};
...