Initialize std::array with a range (pair of iterators) Initialize std::array with a range (pair of iterators) arrays arrays

Initialize std::array with a range (pair of iterators)


With random access iterators, and assuming a certain size at compile-time, you can use a pack of indices to do so:

template <std::size_t... Indices>struct indices {    using next = indices<Indices..., sizeof...(Indices)>;};template <std::size_t N>struct build_indices {    using type = typename build_indices<N-1>::type::next;};template <>struct build_indices<0> {    using type = indices<>;};template <std::size_t N>using BuildIndices = typename build_indices<N>::type;template <typename Iterator>using ValueType = typename std::iterator_traits<Iterator>::value_type;// internal overload with indices tagtemplate <std::size_t... I, typename RandomAccessIterator,          typename Array = std::array<ValueType<RandomAccessIterator>, sizeof...(I)>>Array make_array(RandomAccessIterator first, indices<I...>) {    return Array { { first[I]... } };}// externally visible interfacetemplate <std::size_t N, typename RandomAccessIterator>std::array<ValueType<RandomAccessIterator>, N>make_array(RandomAccessIterator first, RandomAccessIterator last) {    // last is not relevant if we're assuming the size is N    // I'll assert it is correct anyway    assert(last - first == N);     return make_array(first, BuildIndices<N> {});}// usageauto a = make_array<N>(v.begin(), v.end());

This assumes a compiler capable of eliding the intermediate copies. I think that assumption is not a big stretch.

Actually, it can be done with input iterators as well, since the computation of each element in a braced-init-list is sequenced before the computation of the next element (ยง8.5.4/4).

// internal overload with indices tagtemplate <std::size_t... I, typename InputIterator,          typename Array = std::array<ValueType<InputIterator>, sizeof...(I)>>Array make_array(InputIterator first, indices<I...>) {    return Array { { (void(I), *first++)... } };}    

Since *first++ doesn't have any I in it, we need a dummy I to provoke the pack expansion. Comma operator to the rescue, with void() to silence warnings about lack of effects, and also preventing overloaded commas.


Like you have noticed, std::array has no constructors at all (except for the compiler generated default constructor).

This was done on purpose, so it can be statically initialized just like a C array. If you want to fill the array without a static initializer, you will have to copy your data.


You can use BOOST_PP_ENUM as:

include <boost/preprocessor/repetition/enum.hpp>#define INIT(z, i, v) v[i] std::vector<int> v;//fill v with at least 5 items std::array<int,5> a = { BOOST_PP_ENUM(5, INIT, v) };  //MAGIC

Here, the last line is expanded as:

std::array<int,5> a = {v[0], v[1], v[2], v[3], v[4]}; //EXPANDED LINE

which is what you want.