(C 11) Печать последовательности переменных шаблонов

#c #c 11 #sequence #variadic-templates

#c #c 11 #последовательность #переменные-шаблоны

Вопрос:

Мне была поставлена задача метапрограммирования шаблонов с использованием только стандарта C 11 для печати ряда целых чисел в степенях 2, что я успешно выполнил:

 #include <iostream>

template <size_t... Ns>
struct index_sequence
{
    static void print()
    {
        const size_t numbers[] = {Ns...};
        for (const autoamp; number : numbers)
        {
            std::cout << number << ", ";
        }
        std::cout << std::endl;
    }
};

//#include <cmath>

template <size_t Counter, size_t... Rest>
struct make_sequence_impl
{
    using type = typename make_sequence_impl<
        Counter - 1,
        static_cast<size_t>(1) << Counter, Rest...>::type;
};

template <size_t... Rest>
struct make_sequence_impl<0, Rest...>
{
    using type = index_sequence<static_cast<size_t>(1) << 0, Rest...>;
};

template <size_t T>
using make_sequence = typename make_sequence_impl<T>::type;

int main()
{
    make_sequence<N>::print();
}
  

Предполагая, что N равно 5, он будет печатать 1, 2, 4, 8, 16.

Однако впоследствии мне было предложено сделать то же самое, за исключением того, что на этот раз я должен распечатать их в обратном порядке (т. Е. 16, 8, 4, 2, 1 для N = 5). Я совершенно в тупике, но я очень уверен, что это привело лишь к небольшому изменению кода, который я не могу понять, как.

Любая помощь будет оценена. Несколько дней назад увлекся метапрограммированием шаблонов.

Комментарии:

1. использовать reverse_iterator в цикле?

2. Я бы имитировал std::make_integer_sequence , чтобы иметь sequence<Is...> , затем использовал метод преобразования, чтобы иметь sequence<(1 << Is)...> или sequence<(1 << (sizeof...(Is) - 1 -Is))...> .

Ответ №1:

Не уверен, что это минимальное изменение, но вместо последовательности «push_front» вы можете «push_back».

 template <size_t Counter, size_t... Rest>
struct make_sequence_impl
{
    using type = typename make_sequence_impl<
        Counter - 1,
        Rest...,
        static_cast<size_t>(1) << Counter>::type;
};

template <size_t... Rest>
struct make_sequence_impl<0, Rest...>
{
    using type = index_sequence<Rest..., static_cast<size_t>(1) << 0>;
};
  

ДЕМОНСТРАЦИЯ

С моей стороны, я бы имитировал std::make_index_sequence , чтобы иметь 0, 1, 2, .., N-1 , а затем использовать его напрямую:

 emplate <size_t Counter, size_t... Rest>
struct make_sequence_impl
{
    using type = typename make_sequence_impl<
        Counter - 1,
        Counter,
        Rest...>::type;
};

template <size_t... Rest>
struct make_sequence_impl<0, Rest...>
{
    using type = index_sequence<0, Rest...>;
};
  

и затем

 template <std::size_t ... Is>
void print( index_sequence<Is...> )
{
    for (const autoamp; number : {Is...})
    {
        std::cout << number << ", ";
    }
    std::cout << std::endl;
}


template <std::size_t ... Is>
void print_pow2( index_sequence<Is...> )
{
    print(index_sequence<(1u << Is)...>{});
}

template <std::size_t ... Is>
void print_pow2_inv( index_sequence<Is...> )
{
    print(index_sequence<(1u << (sizeof...(Is) - 1 - Is))...>{});
}
  

ДЕМОНСТРАЦИЯ

Комментарии:

1. Боже мой… почему я никогда не думал об этом? Я всегда думал, что вы не можете «push_front» шаблонную последовательность пакетов параметров, и я приближался к моменту изучения реализации функции для обратной распаковки. Большое вам спасибо! Я хотел бы быть лучше в этом…

2. Еще один вопрос о вашей реализации «push_front» и реализации «minic make_index_sequence». Я пробовал оба, и оба они вели себя так, как предполагалось. Существуют ли какие-либо практические различия между ними, или последнее просто реализация, которую вы бы сделали?

3. вероятно, сначала возникла проблема с именованием, поскольку ваше make_sequence имя не совпадает std::make_sequence , make_sequnce_pow было бы лучше назвать. затем, как только последовательность будет выполнена, легче манипулировать ею, чтобы воссоздавать другую каждый раз, когда она нам требуется.