Вложенный статический цикл не работает из-за нехватки 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<2>([&](auto i) {
            std::get<i>(ab) = i;
            static_loop<2>([&](auto j) { std::get<i * j>(ab) = i; });
            // static_loop<2>([&, i = std::integral_constant<size_t, i>()](auto j) { std::get<i * j>(ab) = i; });
        });
        std::cout << a << " " << b << std::endl;
    }
};

Однако она не компилируется при выполнении вложенных циклов.Я бы предположил, что i и j оба constexpr, поэтому i * j допустим в std::get<>, однако компилятор, похоже, не позволяет этого.Можно ли захватить i как constexpr во внутренней лямбде?

Полный пример на Годболт вместе с сообщениями об ошибках.

Ответы [ 2 ]

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

Это как-то работает.Не уверен, что он нарушает какие-либо стандартные правила.

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>());
}

struct A {
    int a;
    int b;
    void run() {
        auto ab = std::make_tuple(std::ref(a), std::ref(b));
        static_loop<2>([&](auto i) {
            std::get<i>(ab) = i;
            static_loop<2>([&](auto j) { auto ii = decltype(i)(); std::get<ii * j>(ab) = ii; });
        });
        std::cout << a << " " << b << std::endl;
    }
};

Захваченное значение может не быть constexpr, но его тип каким-то образом сохраняется.

0 голосов
/ 30 декабря 2018
static_loop<2>([&](auto i) {
    std::get<i>(ab) = i;
    static_loop<2>([&](auto j) { std::get<i * j>(ab) }
}

IDE правильно подчеркивает ошибку для вас.i * j - это умножение двух переменных, это не константа времени компиляции.

Вы можете вкладывать циклы, если переключаетесь на параметры шаблона, а не на аргументы функции.

...