0

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.

Tom Huntington
  • 2,260
  • 10
  • 20
  • 1
    I would change signature to take generator: `template auto create_array_from_generator(Generator gen) -> std::array, N>; // return {{gen(), gen(), gen(), ..}};` – Jarod42 Aug 28 '22 at 09:06
  • @Jarod42 thanks, I don't know why there's a push back on SO for using `std::array` over `std::vector`. You can read the size from just the type. But it just hit me that I should be doing this for my own types (i.e. packing all the compile time information into the type, rather than passing it through the constructor). Solves an irritating workflow pattern I have atm – Tom Huntington Aug 30 '22 at 21:43

2 Answers2

1

Jarod commented that this should be implemented with a generator taking the index, and with c++20 templated lambdas we can do away with the helper function

template <std::size_t N, typename Generator>
auto make_array(Generator gen)
{
    return [&]<std::size_t... I>(std::index_sequence<I...>) -> std::array<std::decay_t<decltype(gen(std::size_t{}))>, N>
    {
        return { {(gen(I))...} };
    }(std::make_integer_sequence<std::size_t, N>{});
}

https://godbolt.org/z/5qGbYWjEh

Tom Huntington
  • 2,260
  • 10
  • 20
0

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)...);
}
Tom Huntington
  • 2,260
  • 10
  • 20