Reputation: 13443
I have a class MyClass
with no default constructor, and I want to create a std::array<MyClass, 8>
. I believe I can initialize my array like this:
std::array<MyClass, 8> my_array = {
{arg00, arg01, /* ... */, arg0N},
{arg10, arg11, /* ... */, arg1N},
/* ... */
{arg70, arg71, /* ... */, arg7N}
};
where argij
is the j-nth argument (out of N) of the i-nth element's constructor (out of 8). Now, spelling out these arguments is a boring and error prone business, and it is much more clear and straightforward to automatically generate/assemble them, which can be done as something like this:
for(uint8_t a = 0; a < 2; ++a) {
for(uint8_t b = 0; b < 2; ++b) {
for(uint8_t c = 0; c < 2; ++c) {
std::tie(arg0, arg1, /* ... */, argN) = generate_args(a, b, c);
/* TODO: do something with arg0, arg1 ... argN */
}
}
}
So, the question: is there a way to create my std::array<MyClass, 8> my_array;
from the dynamically generated constructor arguments?
EDIT:
Currently I have a default constructor on MyClass
, so I can initialize my_array[counter++] = MyClass(args...);
from inside the loops. But I don't like allowing MyClass
to be created in an uninitialized state.
Upvotes: 1
Views: 499
Reputation: 30831
No, you can't work with initializer lists like that. But you might be able to borrow a trick from std::experimental::to_array()
and use a std::index_sequence
template to convert a suitable vector:
template <std::size_t... I>
static constexpr std::array<MyClass, 8>
to_array(std::vector<MyClass>&& v, std::index_sequence<I...>)
{
return { {v[I]...} };
}
const std::array<MyClass, 8> my_array =
[]{
std::vector<MyClass> v;
for(uint8_t a = 0; a < 2; ++a) {
for(uint8_t b = 0; b < 2; ++b) {
for(uint8_t c = 0; c < 2; ++c) {
int arg0, arg1, arg2, arg3;
std::tie(arg0, arg1, arg2, arg3) = generate_args(a, b, c);
v.emplace_back(arg0, arg1, arg2, arg3);
}
}
}
return to_array(std::move(v), std::make_index_sequence<8>{});
}();
If your MyClass
isn't copyable or movable, perhaps directly construct into the array with a similar index sequence template (but generate a
, b
and c
back from the index):
template <std::size_t... I>
constexpr std::array<MyClass, 8>
generate(std::index_sequence<I...>)
{
auto create =
[](std::size_t i) {
const auto& [arg0, arg1, arg2, arg3]
= generate_args((i>>2)&1, (i>>1)&1, (i>>0)&1);
return MyClass{arg0, arg1, arg2, arg3};
};
return { create(I)... };
}
const std::array<MyClass, 8> my_array = generate(std::make_index_sequence<8>{});
Upvotes: 4