从另一个 constexpr std::array 初始化没有默认构造函数的对象的 std::array

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

是否可以初始化一个对象数组,其成员是从另一个普通对象的 constexpr 数组初始化的。例如我有以下

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(  );  

};

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>());
}

用法:

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

Demo

一种解决方案是使用参数包并将其展开以构造数组的初始化列表。

我使用 std::index_sequencestd::make_index_sequence 构造一个参数包,其中包含元素的索引(只是 0、1、2、...、N-1),然后我解压这些索引到初始化列表中:

#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>{});
}

示例:https://godbolt.org/z/dhEGaG