and c++ c++11 constexpr array-initialization

and - constexpr in c++



Crear matriz constexpr N-elemento en C++ 11 (7)

A diferencia de las respuestas en los comentarios a su pregunta, puede hacerlo sin extensiones de compilador.

#include <iostream> template<int N, int... Rest> struct Array_impl { static constexpr auto& value = Array_impl<N - 1, N, Rest...>::value; }; template<int... Rest> struct Array_impl<0, Rest...> { static constexpr int value[] = { 0, Rest... }; }; template<int... Rest> constexpr int Array_impl<0, Rest...>::value[]; template<int N> struct Array { static_assert(N >= 0, "N must be at least 0"); static constexpr auto& value = Array_impl<N>::value; Array() = delete; Array(const Array&) = delete; Array(Array&&) = delete; }; int main() { std::cout << Array<4>::value[3]; // prints 3 }

Hola, estoy aprendiendo C ++ 11, me pregunto cómo hacer un constexpr 0 a n array, por ejemplo:

n = 5; int array[] = {0 ... n};

entonces array puede ser {0, 1, 2, 3, 4, 5}


Basado en la excelente idea de @ Xeo, este es un enfoque que le permite llenar una variedad de

  • constexpr std::array<T, N> a = { fun(0), fun(1), ..., fun(N-1) };
  • donde T es cualquier tipo literal (no solo int u otros tipos válidos de parámetros de plantilla sin tipo), sino también double , o std::complex (desde C ++ 14 en adelante)
  • donde fun() es cualquier función constexpr
  • que es soportado por std::make_integer_sequence desde C ++ 14 en adelante, pero se implementa fácilmente hoy en día tanto con g ++ como con Clang (vea el ejemplo en vivo al final de la respuesta)
  • Uso la implementación de @JonathanWakely en GitHub (Boost License)

Aquí está el código

template<class Function, std::size_t... Indices> constexpr auto make_array_helper(Function f, std::index_sequence<Indices...>) -> std::array<typename std::result_of<Function(std::size_t)>::type, sizeof...(Indices)> { return {{ f(Indices)... }}; } template<int N, class Function> constexpr auto make_array(Function f) -> std::array<typename std::result_of<Function(std::size_t)>::type, N> { return make_array_helper(f, std::make_index_sequence<N>{}); } constexpr double fun(double x) { return x * x; } int main() { constexpr auto N = 10; constexpr auto a = make_array<N>(fun); std::copy(std::begin(a), std::end(a), std::ostream_iterator<double>(std::cout, ", ")); }

Ejemplo en vivo


En C ++ 14 se puede hacer fácilmente con un constructor constexpr y un bucle:

#include <iostream> template<int N> struct A { constexpr A() : arr() { for (auto i = 0; i != N; ++i) arr[i] = i; } int arr[N]; }; int main() { constexpr auto a = A<4>(); for (auto x : a.arr) std::cout << x << ''/n''; }


Pruebe boost::mpl::range_c<int, 0, N> docs .


Utilice C ++ 14 secuencia_iniciativa, o su invariante secuencia_índice

#include <iostream> template< int ... I > struct index_sequence{ using type = index_sequence; using value_type = int; static constexpr std::size_t size()noexcept{ return sizeof...(I); } }; // making index_sequence template< class I1, class I2> struct concat; template< int ...I, int ...J> struct concat< index_sequence<I...>, index_sequence<J...> > : index_sequence< I ... , ( J + sizeof...(I) )... > {}; template< int N > struct make_index_sequence_impl; template< int N > using make_index_sequence = typename make_index_sequence_impl<N>::type; template< > struct make_index_sequence_impl<0> : index_sequence<>{}; template< > struct make_index_sequence_impl<1> : index_sequence<0>{}; template< int N > struct make_index_sequence_impl : concat< make_index_sequence<N/2>, make_index_sequence<N - N/2> > {}; // now, we can build our structure. template < class IS > struct mystruct_base; template< int ... I > struct mystruct_base< index_sequence< I ... > > { static constexpr int array[]{I ... }; }; template< int ... I > constexpr int mystruct_base< index_sequence<I...> >::array[] ; template< int N > struct mystruct : mystruct_base< make_index_sequence<N > > {}; int main() { mystruct<20> ms; //print for(auto e : ms.array) { std::cout << e << '' ''; } std::cout << std::endl; return 0; } output: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19

ACTUALIZACIÓN: puede usar std :: array:

template< int ... I > static constexpr std::array< int, sizeof...(I) > build_array( index_sequence<I...> ) noexcept { return std::array<int, sizeof...(I) > { I... }; } int main() { std::array<int, 20> ma = build_array( make_index_sequence<20>{} ); for(auto e : ma) std::cout << e << '' ''; std::cout << std::endl; }


usando el preprocesador de impulso, es muy simple.

#include <cstdio> #include <cstddef> #include <boost/preprocessor/repeat.hpp> #include <boost/preprocessor/comma_if.hpp> #define IDENTITY(z,n,dummy) BOOST_PP_COMMA_IF(n) n #define INITIALIZER_n(n) { BOOST_PP_REPEAT(n,IDENTITY,~) } int main(int argc, char* argv[]) { int array[] = INITIALIZER_n(25); for(std::size_t i = 0; i < sizeof(array)/sizeof(array[0]); ++i) printf("%d ",array[i]); return 0; }

OUTPUT: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24


#include <array> #include <iostream> template<int... N> struct expand; template<int... N> struct expand<0, N...> { constexpr static std::array<int, sizeof...(N) + 1> values = {{ 0, N... }}; }; template<int L, int... N> struct expand<L, N...> : expand<L-1, L, N...> {}; template<int... N> constexpr std::array<int, sizeof...(N) + 1> expand<0, N...>::values; int main() { std::cout << expand<100>::values[9]; }