简体   繁体   中英

Create std::array<T, N> from constructor argument list

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.

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)...);
}

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>{});
}

https://godbolt.org/z/PMPhvW81q

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM