Question

Continuing my journey into the world of variadic templates, I encountered another problem.

Assuming the following template class:

template < typename T >
struct foo 
{
    //default implementation
};

it is possible to partially specialize it for variadic template instantiations like this:

template < template < typename ... > class T, typename ...Args >
struct foo< T< Args... > >
{
    //specialized implementation
};

With this, foo< int > will correspond to the default implementation and foo< std::tuple< int, char > > to the specialized implementation.

However, things become more complicated when using several template parameters. For example, if we have the following template class

template < typename T, typename U >
struct bar {};

and we want to partially specialize it as we did for foo, we cannot do

template < template < typename ... > class T, typename ...TArgs,
           template < typename ... > class U, typename ...UArgs >
struct bar< T< TArgs... >, U< UArgs... > > {};

//This would correspond to the specialized version with
//T=std::tuple,
//TArgs=int,char
//U=std::tuple,
//UArgs=float
bar< std::tuple< int, char >, std::tuple< float > > b;

Indeed, if I am correct, we can only have one template parameter pack and it must be positioned at the end of the parameter list. I understand why this is mandatory in template declarations, but for certain partial template specialization (like the example above), this should not be an issue.

Is it possible to achieve partial template specialization with multiple template parameter packs?


Edit: Now I feel silly...the code I gave above compiles perfectly (at least with gcc 4.5). The compile error I had was not because of multiple parameter packs, but because of their use as member functions parameters. In the partial specialization of bar, I tried to define a member function that takes both TArgs and UArgs parameters:

template < template < typename ... > class T, typename ...TArgs, 
           template < typename ... > class U, typename ...UArgs >
struct bar< T< TArgs... >, U< UArgs... > >
{
    void method( TArgs... targs, UArgs... uargs ) //compile error here
    {
    }
};

On the member function declaration, gcc gives me the error

parameters packs must be at the end of the parameter list.

As far as I can tell, the compiler should be able to define the correct member function for a given template instantiation, e.g. bar< std::tuple< int, char >, std::tuple< float > > should contain a member function void method( int, char, float ). Am I doing something wrong? Or am I trying to do something that is not possible? If so, is there a good reason why this is not possible?

Was it helpful?

Solution

Probably this answer won't clear your question directly, but the following code compiled on ideone(gcc-4.5.1) when I tested.

#include <cstdio>
#include <tuple>

template< class, class > struct S {
  S() { puts("primary"); }
};

template<
  template< class... > class T, class...TArgs
, template< class... > class U, class...UArgs
>
struct S< T< TArgs... >, U< UArgs... > > {
  S() { puts("specialized"); }
};

int main()
{
  S< int, int >  p;                                       // "primary"
  S< std::tuple< int, char >, std::tuple< float > >  s;   // "specialised"
}

I'm not sure this code is strictly conformant, but as far as I read N3225 14.5.3, I couldn't find the statement which mentions that template parameter pack has to be the last template parameter.

Edit:
I reread N3225 and found the following statements:

8.3.5/4 If the parameter-declaration-clause terminates with an ellipsis or a function parameter pack (14.5.3), the number of arguments shall be equal to or greater than the number of parameters that do not have a default argument and are not function parameter packs.

14.8.2.5/10 [Note: A function parameter pack can only occur at the end of a parameter-declarationlist(8.3.5). -end note]

So, as you mentioned, function parameter pack has to be the last parameter unfortunately.
A non-template member function of a class template is an ordinary function for that class when it is instantiated(fully specialized). So I wish that the code in this question can be compiled logically, as a special case.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top