简体   繁体   中英

Ability to multiply two parameter packs in C++ 11 in dot product fashion via variadic templates

template<class...A, class...B> void func(A...arg1,int sz1, int sz2, B...arg2)
{
std::cout << "sizeof parameter pack for A = " << sizeof...(arg1) << std::endl;
std::cout << "sizeof parameter pack for B = " << sizeof...(arg2) << std::endl;
}

using namespace std;

int main(void)
{
   func<int,int,int,int>(1,2,3,4,4,4,5,6,7,8);

}

My question is how can i peel the first parameter of each of these packs and multiply them and then sum them with recursive call to reduced parameter pack of both the packs.

Esentially I want to implement : SUM(A[i] * B[i])

You can actually do that without recursion.

template<class...A, class...B> int func(A...arg1, int sz1, int sz2, B...arg2)
{
    std::vector<int> p = {(arg1 * arg2)...};
    return std::accumulate(p.begin(), p.end(), 0);
}

There is no needs of recursion (if you don't want a C++11 constexpr returning function).

Suggestion: instead of a couple of variadic arguments use a couple of C-style arrays as follows

template <typename T, std::size_t N>
T func (T const (&a1)[N], T const (&a2)[N])
 {
   T ret {};

   for ( auto ui { 0u } ; ui < N ; ++ui )
      ret += a1[ui] * a2[ui];

   return ret;
 }

This way you have: (1) an homogeneous T type instead a couple of variadic type lists and (2) that the two list must be of the same size N or the function doesn't match. I suppose they are advantages if you want a sum(a[i] * b[i])

The function should be called with a couple of initialization list (that is: wrapping in brackets the two lists)

// print 70 
std::cout << func({1, 2, 3, 4}, {5, 6, 7, 8}) << std::endl;

Different if you need a constexpr function: the func() can be constexpr starting from C++14 but not in C++11.

If you want a C++11 constexpr function you need it recursive but there no need of "peel the first parameter of each of these packs": you can use and index (with a default starting value of zero)

template <typename T, std::size_t N>
constexpr T func (T const (&a1)[N], T const (&a2)[N], std::size_t pos = 0u)
 {
   return pos < N 
      ? a1[pos] * a2[pos] + func(a1, a2, pos+1u)
      : T{0};
 }

-- EDIT --

The OP says

My whole aim is to do this using parameter packs only :)

I see...

Well, I suppose that, in C++11, you can use trick of the initialization of an unused array

template <typename ... As, typename ... Bs>
auto func (As ... args1 ,int, int, Bs ...args2)
    -> typename std::common_type<As..., Bs...>::type
 {
   using unused = int[];

   typename std::common_type<As..., Bs...>::type ret{};

   (void)unused { 0, ( ret += args1 * args2, 0 ) ... };

   return ret;
 }

If you can use C++17, you can write

template <typename ... As, typename ... Bs>
auto func (As ... args1 ,int, int, Bs ...args2)
 {
   return ( (args1 * args2) + ... );
 }

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