C ++ 14: Как использовать шаблон переменной для создания массива значений 1-100

Я хочу получить массив значений int buf[]={1...100}, Я хотел бы, чтобы этот массив мог быть построен во время компиляции, используя шаблон variadic. Это как понимание списка Python / Haskell и т. Д.

Но может ли шаблон c ++ 11/14 сделать это и как?
Спасибо

2

Решение

Если вы действительно хотите сделать это во время компиляции. Вы могли бы сделать это с integer_sequence и std::array

#include <utility>
#include <array>

template <int... Is> // when called below, Is will be 0 - N
constexpr std::array<int, sizeof...(Is)> make_inc_array_impl(
std::integer_sequence<int, Is...>) {
return {{(Is + 1)...}}; // +1 to start at one instead of [0, 1, ...]
}template <std::size_t N>
constexpr std::array<int, N> make_inc_array() {
return make_inc_array_impl(std::make_integer_sequence<int, N>{});
}

Затем позвоните с вашим размером

constexpr auto a = make_inc_array<100>(); // [1, 2, ..., 100]

Это гораздо менее гибко, чем понимание списка, и вам, вероятно, будет гораздо лучше использовать std::iota и инициализация во время выполнения.

3

Другие решения

C ++ 14 позволяет циклы во время компиляции.

constexpr auto make_upto_100() {
std::array< int, 100 > ret = {};
for ( int i = 0; i != 100; ++ i ) ret[i] = i + 1;
return ret;
}

C ++ 11 позволяет утилиту, как make_index_sequence что может быть больше похоже на ваше мышление. (C ++ 14 также имеет std::[make_]index_sequence.)

template< std::size_t ... i >
struct index_sequence
{ typedef index_sequence< i ..., sizeof ... (i) > next; };

template< std::size_t last >
struct index_seq_maker
{ typedef typename index_seq_maker< last - 1 >::type::next type; };

template<>
struct index_seq_maker< 0 >
{ typedef index_sequence<> type; };

template< std::size_t n >
using make_index_sequence = typename index_seq_maker< n >::type;

template< int ... i >
constexpr
std::array< int, 100 >
make_upto_100( index_sequence< i ... > )
{ return {{ i + 1 ... }}; }

constexpr
std::array< int, 100 > upto_100() = make_upto_100( make_index_sequence< 100 >{} );
4

Это должно работать для C ++ 14. Он работает путем рекурсивного создания шаблона, чтобы инициализировать все значения как constexpr, Вы должны иметь возможность изменить размер последовательных значений на любой другой, изменив параметр шаблона. Обратите внимание, что для очень больших массивов он может достигнуть предела рекурсии:

#include <array>

template<int NumVal, int ArrSize>
constexpr void setVal(std::array<int, ArrSize> &constArr) {
std::get<NumVal>(constArr) = NumVal + 1;
if(NumVal) setVal<NumVal ? NumVal - 1 : 0, ArrSize>(constArr);
}

template<int ArrSize>
constexpr auto arrRange() -> std::array<int, ArrSize> {
std::array<int, ArrSize> tmp{};
setVal<ArrSize - 1, ArrSize>(tmp);
return tmp;
}

constexpr std::array<int, 100> constArr = arrRange<100>();

int main() {
for(int itr = 0; itr < 100; ++itr) printf("%d ", constArr[itr]);
}
1

Ну, это не время компиляции, но обычно я ожидаю, что большинство кода будет использовать std::iota. В некоторых случаях это может быть быстрее, чем волшебство времени компиляции, так как массивы времени компиляции должны храниться в исполняемом файле. .data сегмент; если массив достаточно большой, чтение дополнительных страниц диска из .data может закончиться медленнее, чем запись на страницы в памяти, которые извлекаются из ОС.

Простое использование будет:

int buf[100];
std::iota(&buf[0], &buf[100], 1);

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

0
По вопросам рекламы [email protected]