Search code examples
c++arraysc++20initializer-listparameter-pack

Arrays of Objects without standard constructor using Parameter Packs


I want to fill an std::array of size N with objects without a standard constructor.

std::array<non_std_con,N> myArray;

(It's std::array<kissfft<float>, 64> in my case, to be specific)

This results in the error

error: use of deleted function ... standard constructor

Setup

You can fill the array using an intializer list:

std::array<non_std_con,N> myArray{non_std_con{init1,init2},non_std_con{init1,init2},...}

The initializer list needs N objects.

And you can build an array using parameter packs:

template <class... Params>
auto constexpr build_array(Params... params)
{
    std::array<non_std_con, sizeof...(params)> myArray= {params...};
    return myArray;
}

Question

Is there a way to use this the other way around and build a parameter pack out of a single argument:

std::array<non_std_con,N> buildArray(inti1,init2);

This would build an array of N non_std_con where every object is initialized with {init1,init2}

Thank you for your time


Solution

  • You could write:

    #include <array>
    #include <utility>
    #include <iostream>
    
    namespace detail
    {
        template <
            typename T,
            std::size_t ... Is
        >
        constexpr std::array<T, sizeof...(Is)> create_array(T value, std::index_sequence<Is...>)
        {
            // cast Is to void to remove the warning: unused value
            return {{(static_cast<void>(Is), value)...}};
        }
    }
    
    template<
        typename T,
        int N,
        typename... CtorAgrs
    >
    constexpr std::array<T, N> buildArray(CtorAgrs... args)
    {
        using Array = std::array<T, N>;
        return detail::create_array<T>(T{args...}, std::make_index_sequence<N>());
    }
    
    
    struct Foo{
        int a, b;
        constexpr Foo(int a, int b) : a(a), b(b)
        {
        }
    };
    
    int main() {
        constexpr auto array = buildArray<Foo, 10>(1, 2);
    
        for(const auto& f : array){
            std::cout << f.a;
            std::cout << "\n";
        }
    }
    

    or with C++-20 simply:

    template<
        typename T,
        int N,
        typename... CtorAgrs
    >
    constexpr std::array<T, N> buildArray(CtorAgrs&&... args)
    {
        auto doBuildArray = [&]<std::size_t ... Is>(std::index_sequence<Is...>)
        ->  std::array<T, N>
        {
            // cast Is to void to remove the warning: unused value
            return {{(static_cast<void>(Is), T{args...})...}};
        };
    
        return doBuildArray(std::make_index_sequence<N>());
    }