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