Initialize all elements or std::array with the same constructor arguments

You may use delegating constructors and pack expansion

struct A {
    A(int b, int c) : b(b), c(c) { }
    A(const A&) = delete;
    A(A&&) = delete;
    int b;
    int c;
};

template <size_t N>
struct B {
  B (int b, int c) : B(b, c, std::make_index_sequence<N>{}) {}

  template<size_t... Is>
  B (int b, int c, std::index_sequence<Is...>) :
    arr{(Is, A{b, c})...}
  {}

  std::array<A, N> arr;
};

Live

Note if the move and copy constructors are deleted, this will only work after C++17.


For both C++11 and C++14 (i.e.: pre-C++17) what you want can be achieved by means of template metaprogramming.

You could declare the following helper class template, array_maker<>, which has a static member function template, make_array, that calls itself recursively:

template<typename T, std::size_t N, std::size_t Idx = N>
struct array_maker {
    template<typename... Ts>
    static std::array<T, N> make_array(const T& v, Ts...tail) {
        return array_maker<T, N, Idx-1>::make_array(v, v, tail...);
    }
};

Then, specialize this class template for the case Idx equal to 1, i.e.: the base case of the recursion:

template<typename T, std::size_t N>
struct array_maker<T, N, 1> {
    template<typename... Ts>
    static std::array<T, N> make_array(const T& v, Ts... tail) {
        return std::array<T, N>{v, tail...};
    }
};

Finally, it can be used in the constructor of your template this way:

template <size_t NR_A>
struct B {
  B (int b, int c) : mAs{array_maker<A, NR_A>::make_array(A{b,c})}
  {}    
  std::array<A, NR_A> mAs;
};

Tags:

C++

Templates