The desired behaviour is that of emplace
called N
times.
Very similar to this question Initializing a std::array with a constant value. Except instead of calling the copy constructor given some T
, you are given some argument list for which you call the corresponding constructor of T
.
Pseudo code:
template <typename ...Args>
std::array<T, N> create_array(Args&&... args)
{
return { T(args...), T(args...), .... };
}
For example, this is necessary when T
has members that are (smart) pointers and you want these pointers to reference unique objects.
CodePudding user response:
Modifying this answer, I came up with:
namespace detail
{
template <typename T, std::size_t ... Is, typename ...V>
constexpr std::array<T, sizeof...(Is)>
create_array(std::index_sequence<Is...>, V&&... values)
{
// cast Is to void to remove the warning: unused value
return { {(static_cast<void>(Is), T(values...))...} };
}
}
template <typename T, std::size_t N, typename ...V>
constexpr std::array<T, N> create_array(V&&... values)
{
return detail::create_array<T>(std::make_index_sequence<N>(), std::forward<V>(values)...);
}
CodePudding user response:
Jarod commented that this should be implemented with a generator, and with c 20 templated lambdas we can do away with the helper function
template <std::size_t N, typename Generator>
auto create_array_from_generator(Generator gen)
{
return [&]<std::size_t... I>(std::index_sequence<I...>) -> std::array<std::decay_t<decltype(gen())>, N>
{
return { {(static_cast<void>(I), gen())...} };
}(std::make_integer_sequence<std::size_t, N>{});
}