88

Hello i'm learning C++11, I'm wondering how to make a constexpr 0 to n array, for example:

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

so array may be {0, 1, 2, 3, 4, 5}

2
  • 3
    Here's a recent similar question using std::arrays. Commented Sep 26, 2013 at 9:45
  • We're at C++17 now. So, @abyx 's answer is now the best answer, because it can no longer be considered to be dependent on "compiler extensions". Commented Apr 22, 2019 at 17:04

9 Answers 9

75

In C++14 it can be easily done with a constexpr constructor and a loop:

#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'; } 
Sign up to request clarification or add additional context in comments.

7 Comments

this is concise. Why is : arr() necessary?
@IceFire probably because you cannot have uninitialized fields in constexpr function (which is a constructor here). Just a guess.
How could you pass a function to A that would be applied to all array elements? When using template <int N, class Function> ... constexpr A(Function f) : arr() {... I can't figure out how to instantiate the struct.
Note: doesn't work with Visual Studio 15, might be supported in Visual Studio 2017.
Great answer and this work nicely for me. Just wondering - in the newer versions of C++ are there any new syntactical ways of doing this?
|
58

Unlike those answers in the comments to your question, you can do this without compiler extensions.

#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 } 

2 Comments

@Kal nice, but "only" works for int or other types that can appear as non-type template parameters (so not for e.g. double). See my answer for the general solution.
Nice. But I think I would hide the recursive variadic template behind a non-variadic public interface, to avoid confusion if somebody tries Array<9,3,5>.
40

Based on @Xeo's excellent idea, here is an approach that lets you fill an array of

  • constexpr std::array<T, N> a = { fun(0), fun(1), ..., fun(N-1) };
  • where T is any literal type (not just int or other valid non-type template parameter types), but also double, or std::complex (from C++14 onward)
  • where fun() is any constexpr function
  • which is supported by std::make_integer_sequence from C++14 onward, but easily implemented today with both g++ and Clang (see Live Example at the end of the answer)
  • I use @JonathanWakely 's implementation at GitHub (Boost License)

Here is the code

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, ", ")); } 

Live Example

1 Comment

where auto is any literal type Isn't it a std::array of literal types, in auto a = make_array<N>(fun);, equivalent to auto a = std::array<decltype(fun(0)), N>{fun(0), fun(1), ..};? Also, the example constexpr auto a = {1,2}; deduces a to be a std::initializer_list, which isn't yet required to be a literal type (-> no constexpr). (I know it's rather pedantic, but I was confused at first glance.)
6

Use C++14 integral_sequence, or its invariant index_sequence

#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 

UPDATE: You may use 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; } 

2 Comments

Clang + libc++ tip of tree support this. Pass -std=c++1y.
I use Clang 3.3 and GCC 4.8.1 with -std=c++11 options.
3

For std::array in C++17, constexpr function are also accepted Note that the var 'arr' must be initialized by constexpr required.
(initialize: same meaning with answer of @abyx)

#include <array> constexpr std::array<int, 3> get_array() { std::array<int, 3> arr{0}; arr[0] = 9; return arr; } static_assert(get_array().size() == 3); 

Comments

2

With C++17 this can be done easily as std::array::begin is marked constexpr.

template<std::size_t N> std::array<int, N + 1> constexpr make_array() { std::array<int, N + 1> tempArray{}; int count = 0; for(int &elem:tempArray) { elem = count++; } return tempArray; } int main() { //-------------------------------vv------>pass the size here constexpr auto arr = make_array<5>(); //lets confirm if all objects have the expected value for(const auto &elem: arr) { std::cout << elem << std::endl; //prints 1 2 3 4 5 with newline in between } } 

Demo

Comments

1
#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]; } 

Comments

-2

Using boost preprocessor, it's very 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 

1 Comment

I think you could also use one of the ENUM macros, e.g. BOOST_PP_ENUM_PARAMS(25, BOOST_PP_EMPTY()), instead of the REPEAT+COMMA_IF
-6

Consider boost::mpl::range_c<int, 0, N> instead.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.