intializing a std::array of objects that don't have default constructor from another constexpr std::array

Viewed 88

Is it possible to initialize an array of objects whose members are initialized from another constexpr array of trivial objects. For example I have the following

struct X
{
  X(int y): _x(y){}
  int _x;
};

struct Z
{
  static constexpr std::array<int, 4> arr = {1,6,0,4};
  

  // How does one implement make_array below that constructs
  // X[0] from arr[0], X[1] from arr[1], etc.
  // Is it even feasible in C++14/17?
  std::array<X, arr.size()> xArr = make_array(  );  

};
2 Answers

With std::index_sequence:

template <typename T, typename U, std::size_t N, std::size_t ... Is>
constexpr std::array<T, N> make_array(const std::array<U, N>& a, std::index_sequence<Is...>)
{
    return {{T(a[Is])...}};
}

template <typename T, typename U, std::size_t N>
constexpr std::array<T, N> make_array(const std::array<U, N>& a)
{
    return make_array<T>(a, std::make_index_sequence<N>());
}

Usage:

static constexpr std::array<int, 4> arr = {1,6,0,4};
  
/*constexpr*/ std::array<X, arr.size()> xArr = make_array<X>(arr);  

Demo

One solution is to use a parameter pack and expand it to construct an initializer list for the array.

I use a std::index_sequence and std::make_index_sequence to construct a parameter pack which contains the index of the elements (simply 0, 1, 2, ..., N-1) then I unpack those indexes into an initializer list :

#include <array>
#include <utility>

// O : output type; type to convert elements to
// T : input type
// N : number of elements
// I : parameter pack of indexes
template<class O, class T, std::size_t N, std::size_t ... I>
auto make_array_impl(const std::array<T, N> & p_input, std::index_sequence<I...>) -> std::array<O, N>
{
    // Unpack the parameter pack into an initializer list
    // Constructs an `O` from each element in order
    return {O{p_input[I]}...};
}


// O : output type; type to convert elements to
// T : input type
// N : number of elements
template<class O, class T, std::size_t N>
auto make_array(const std::array<T, N> & p_input)
{
    // Helper function to automatically generate the parameter pack
    return make_array_impl<O>(p_input, std::make_index_sequence<N>{});
}

Example : https://godbolt.org/z/dhEGaG

Related