Search code examples
c++c++14variadic-templatesparameter-pack

unpack multiple parameter packs to initialize a 2d array


I'm trying to unpack multiple parameter packs so that arr[i][j] = X(i,j). However I get the following error with the current approach below. Are there approaches to achieve the above using C++14/17?

// Non copyable and default constructable
struct X
{
    X(const X&) = delete;
    X(int x, int y) : _x(x), _y(y)
    {}
    int _x;
    int _y;
};

X getX(int i, int j)
{
    return X(i,j);
}


template <std::size_t ...Xidx, std::size_t ... Yidx>
auto make_2d_array(std::index_sequence<Xidx...>, std::index_sequence<Yidx...>)
{
    std::array<std::array<X,sizeof...(Xidx)>, sizeof...(Yidx)> arr = {getX(Xidx, Yidx)...};
    return arr;
}

static constexpr std::size_t M = 5;
static constexpr std::size_t N = 6;

int main()
{
    std::array<std::array<X,M>, N> arr = make_2d_array(std::make_index_sequence<M>{}, std::make_index_sequence<N>{});
}

Error

<source>:26:87: error: pack expansion contains parameter packs 'Xidx' and 'Yidx' that have different lengths (5 vs. 6)
    std::array<std::array<X,sizeof...(Xidx)>, sizeof...(Yidx)> arr = {getX(Xidx, Yidx)...};
                                                                           ~~~~  ~~~~ ^
<source>:35:42: note: in instantiation of function template specialization 'make_2d_array<0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 5>' requested here
    std::array<std::array<X,M>, N> arr = make_2d_array(std::make_index_sequence<M>{}, std::make_index_sequence<N>{});
                                         ^
1 error generated.
Compiler returned: 1

Solution

  • I would do this

    template<std::size_t... XIs, std::size_t... YIs>
    std::array<std::array<X, sizeof...(XIs)>, sizeof...(YIs)> make_2d_array(std::index_sequence<XIs...>, std::index_sequence<YIs...>)
    {
        return {
            [](auto YI) -> std::array<X, sizeof...(XIs)> {
                return {getX(XIs, YI)...};
            }(YIs)...
        };
    }
    

    Yes, it is somewhat terrible. The principle is simply that we need to syntactically separate XIs and YIs enough that each ... expansion only unpacks one of them, and we need two expansions to do the "product" instead of the "zipping".