Home > Mobile >  Can multiple parameter packs be expanded in a single expression?
Can multiple parameter packs be expanded in a single expression?

Time:11-27

I want to get a matrix from two parameter packs like the following:


template < typename T1, typename T2 > struct Multi{};
template < int ... n > struct N{};

void Print( int n ){ std::cout << n << std::endl; }

template < int ... n1, int ... n2 >
struct Multi< N<n1...>, N<n2...>> 
{
    Multi() 
    {   
        using expander = int[];

        // No idea which syntax should be used here:
        expander{ 0,((void)Print(n1...*n2),0)... };
    }
};


int main()
{
    Multi< N<1,2,3,4>, N< 10,20> >{};
}

The result should be

10 20 30 40 20 40 60 80

How can I do this?

CodePudding user response:

No need to use the dummy arrays when you have fold expressions.

The naive (Print(n1 * n2), ...); wouldn't work (it expects the packs to have the same size, and would print N numbers instead of N2).

You need two nested fold expressions. In the inner one, you can prevent one of the packs from being expanded by passing it as a lambda parameter.

([](int n){(Print(n1 * n), ...);}(n2), ...);

CodePudding user response:

This is not single expression, but you can expand it and use for loop

template < int ... n1, int ... n2 >
struct Multi< N<n1...>, N<n2...>> 
{
    Multi() 
    {
        for(auto j : {n2...})
        for(auto i : {n1...})
           std::cout << i*j << '\n';
    }
};

WandBox

CodePudding user response:

I kind of assume that the output in your code is to check the compile time evaluation, since the output to std::cout only works at runtime.

Another option is not to use structs but to use constexpr functions, they look more like regular c code. And you van validate the correctness at compile time using static_asserts. I did add some output at the end of my example live demo here : https://onlinegdb.com/iNrqezstg

#include <array>
#include <iostream>

template<int... n>
constexpr auto array()
{ 
    return std::array<int,sizeof...(n)>{n...}; 
};

template<std::size_t N, std::size_t M>
constexpr auto multiply(const std::array<int, N>& arr1, const std::array<int, M>& arr2)
{
    std::array<int, N* M> result{};
    std::size_t index{ 0 };
    for (std::size_t n = 0; n < N; n  )
    {
        for (std::size_t m = 0; m < M; m  )
        {
            result[index] = arr1[n] * arr2[m];
              index;
        }
    }
    return result;
}

template<typename container_t>
void show(const char* msg, const container_t& values)
{
    std::cout << msg << " : ";
    bool comma{ false };
    for (const auto& value : values)
    {
        if (comma) std::cout << ", ";
        std::cout << value;
        comma = true;
    }

    std::cout << "\n";
}


int main()
{
    constexpr auto arr1 = array<1, 2, 3, 4>();
    constexpr auto arr2 = array<10, 20>();
    constexpr auto result = multiply(arr1, arr2);

    static_assert(arr1[0] == 1, "");
    static_assert(arr2[1] == 20, "");
    static_assert(result[0] == 10, "");
    static_assert(result[1] == 20, "");
    static_assert(result[6] == 40, "");

    show("arr1", arr1);
    show("arr2", arr2);
    show("result", result);

    return 0;
}
  • Related