Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

template template syntax problems with variadic templates

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;
    }
like image 865
Klaus Avatar asked Nov 16 '12 10:11

Klaus


People also ask

What are variadic templates in c++?

Variadic templates are class or function templates, that can take any variable(zero or more) number of arguments. In C++, templates can have a fixed number of parameters only that have to be specified at the time of declaration. However, variadic templates help to overcome this issue.

What is a parameter pack in C++?

Parameter packs (C++11) A parameter pack can be a type of parameter for templates. Unlike previous parameters, which can only bind to a single argument, a parameter pack can pack multiple parameters into a single parameter by placing an ellipsis to the left of the parameter name.

What is Pack expansion?

Pack expansion A pattern followed by an ellipsis, in which the name of at least one parameter pack appears at least once, is expanded into zero or more comma-separated instantiations of the pattern, where the name of the parameter pack is replaced by each of the elements from the pack, in order. template<class...


2 Answers

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
}
like image 165
ecatmur Avatar answered Nov 15 '22 08:11

ecatmur


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).

like image 26
BЈовић Avatar answered Nov 15 '22 09:11

BЈовић