I am wondering if it's possible to initialize a std::array
of objects with an implicitly deleted default constructor, without knowing a priori the size of the array because it's a template argument and so having lost the possibility of using an initializer list. Code follows, it breaks with a "call to implicitly-deleted default constructor of std::array<A, 3UL>
"
struct A {
A (int b, int c) : mb(b), mc(c) { }
int mb;
int mc;
};
template <size_t NR_A>
struct B {
B (int b, int c) :
// <- how to initialize mAs here?
{ }
std::array<A, NR_A> mAs;
};
B<3> inst(1,1);
edit: I'd like to initialize all the A
's of mAs
to A{1,1}
std::array::array For elements of a class type this means that their default constructor is called. For elements of fundamental types, they are left uninitialized (unless the array object has static storage, in which case they are zero-initialized).
In c++ , the name of the array is a pointer to the first element in the array. So when you do *state = *arr , you store the value at arr[0] in the variable state. Show activity on this post. The name of an array is the address of the first element in it.
std::array contains a built-in array, which can be initialized via an initializer list, which is what the inner set is. The outer set is for aggregate initialization.
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;
};
here's a solution I came up with (requires c++17)
template<typename T, std::size_t N, std::size_t index_t = N, typename... Ts>
constexpr auto make_array(T t, Ts... ts)
{
if constexpr (index_t <= 1) {
return std::array<T, N> {t, ts...};
} else {
return make_array<T, N, index_t - 1>(t, t, ts...);
}
}
This is a modification of one of the previous solution that had an array maker struct. This does the same just in a more concise form.
It takes in a single item and keeps doubling down on that item until it reaches a depth of 1,then returns an array from the unfolding. I didn't realize that you a fold expression can be used even though no arguments are passed through it. Although I know this implicitly from things like printf.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With