Я хочу получить массив значений int buf[]={1...100}
, Я хотел бы, чтобы этот массив мог быть построен во время компиляции, используя шаблон variadic. Это как понимание списка Python / Haskell и т. Д.
Но может ли шаблон c ++ 11/14 сделать это и как?
Спасибо
Если вы действительно хотите сделать это во время компиляции. Вы могли бы сделать это с 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
и инициализация во время выполнения.
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 >{} );
Это должно работать для 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]);
}
Ну, это не время компиляции, но обычно я ожидаю, что большинство кода будет использовать std::iota
. В некоторых случаях это может быть быстрее, чем волшебство времени компиляции, так как массивы времени компиляции должны храниться в исполняемом файле. .data
сегмент; если массив достаточно большой, чтение дополнительных страниц диска из .data
может закончиться медленнее, чем запись на страницы в памяти, которые извлекаются из ОС.
Простое использование будет:
int buf[100];
std::iota(&buf[0], &buf[100], 1);
Честно говоря, я бы начал здесь и только начал изучать магию шаблонов, если у вас есть проверенная проблема с производительностью при инициализации во время выполнения.