7
votes

I have a problem with variadic template templates:

            template <typename T> class A { };
            template< template <typename> class T> class B { };
            template <template <typename> class T, typename parm> class C { typedef T<parm> type; };
            template <typename... types> class D { };
            template <template <typename...> class T, typename ... parms> class E { typedef T<parms...> type; };

            // How to pass list in list??
            template < template <typename...> class ...T, ???>
            class F
            {
            };

First, pass a type to the template, no problem:

            A<int> a; //ok

Now, I want to create an instance from B, but no way to pass the template template param:

            B<A> b; // ok, but no chance to submit <int> inside A!

So I have to extend the parameter list:

            C<A, int> c; // ok, this transport int as parm into A

Now I play with variadic templates in standard fashion:

            D<> d1; // ok
            D<int, float, double> d2;   //ok

Passing parameters into the variadic part is also strait forward:

            E<D> e1;    //ok
            E<D, double, float, int> e2; //ok

BUT: If I want to have a list of lists, I find no syntax which will me enable to pass parameter lists to the list of types. What my intend is something like this. but also the above example shows that B<A<int>> b; is an error! So the following example couldn't work :-(

            F< D< int, float>, D< int>, D <float, float, float> > f;

My target is to unroll the list of lists via template specialization. Any hints?

My solution after I understood the problem. Thanks!

Now I can unroll my variadic variadic template template as in the following example. The simple problem was, that I wait for a template class and not for a simple type. Sometimes, the solution can be so easy :-)

Thats my working result now:

    template <typename ... > class D;

    template <typename Head, typename... types>
    class D<Head, types...>
    {
       public:
          static void Do() { cout << "AnyType" << endl; D<types...>::Do(); }
    };

    template<>
    class D<>
    {
       public:
          static void Do() { cout << "End of D" << endl; }
    };

    template < typename ...T> class H;

    template < typename Head, typename ...T>
    class H<Head, T...>
    {
       public:
          static void Do()
          {
             cout << "unroll H" << endl;
             cout << "Subtype " << endl;
             Head::Do();
             H<T...>::Do();
          }
    };

    template <>
    class H<>
    {
       public:
          static void Do() { cout << "End of H" << endl; }
    };


    int main()
    {
       H< D<int,int,int>, D<float, double, int> >::Do();
       return 0;
    }
2

2 Answers

2
votes

You can unpack one variadic specialisation at a time through specialisation:

template<typename...> struct S;
template<> struct S<> { constexpr static int n = 0; };
template<template<typename...> class T, typename... Us, typename... Vs>
struct S<T<Us...>, Vs...> {
    constexpr static int n = sizeof...(Us) + S<Vs...>::n;
};

template<typename...> struct D {};

#include <iostream>
int main() {
    std::cout << S<D<int, int, int>, D<int, int>, D<int>>::n << '\n'; // prints 6
}
1
votes

Like this :

template < template <typename...> class ...T >
class F
{
};
int main()
{
  F< D, D > f;
}

So, what F is expecting is a variadic template class, that takes another variadic template class as it's argument.

You can not expand the arguments of the arguments of the template class argument. If you specialize the template class that you pass as argument, then you'll get the specialized version.

This :

 F< D< int, float>, D< int>, D <float, float, float> > f;

doesn't work, since F expects variadic template class, taking variadic template classes as types, and D< int, float> is not a template anymore (it is a concrete class).