具有多个模板参数包的部分模板专业化

时间:2011-01-16 16:53:45

标签: c++ templates c++11 variadic-templates

继续my journey into the world of variadic templates,我遇到了另一个问题。

假设以下模板类:

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

可以对变量模板实例化进行部分专门化,如下所示:

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

有了这个,foo< int >将对应于专门实现的默认实现和foo< std::tuple< int, char > >

但是,使用多个模板参数时,事情变得更加复杂。例如,如果我们有以下模板类

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

我们希望像foo那样对其进行部分专业化,我们无法做到

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;

实际上,如果我是正确的,我们只能有一个模板参数包,它必须位于参数列表的末尾。我理解为什么这在模板声明中是强制性的,但对于某些部分模板特化(如上面的例子),这应该不是问题。

是否可以使用多个模板参数包实现部分模板专业化?


编辑:现在我觉得很傻......我上面给出的代码完美编译(至少使用gcc 4.5)。我遇到的编译错误不是因为多个参数包,而是因为它们被用作成员函数参数。在bar的部分特化中,我尝试定义了一个同时包含TArgsUArgs参数的成员函数:

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
    {
    }
};

在成员函数声明中,gcc给出了错误

  

参数包必须位于参数列表的末尾。

据我所知,编译器应该能够为给定的模板实例化定义正确的成员函数,例如: bar< std::tuple< int, char >, std::tuple< float > >应包含成员函数void method( int, char, float )。难道我做错了什么?还是我想做一些不可能的事情?如果是这样,是否有充分理由说明这是不可能的?

1 个答案:

答案 0 :(得分:6)

这个答案可能不会直接解决你的问题, 但是当我测试时,下面的代码在ideone(gcc-4.5.1)上编译。

#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"
}

我不确定这段代码是否严格符合,但是 据我读N3225 14.5.3,我找不到提到的陈述 该模板参数包必须是最后一个模板参数。

编辑:
我重读了N3225并发现了以下声明:

  

8.3.5 / 4如果是参数声明子句   以省略号或   功能参数包(14.5.3),.   参数的数量应等于   或大于   没有默认值的参数   论证而不是功能   参数包。

     

14.8.2.5/10 [注意:函数参数包只能出现在   结束了   参数declarationlist(8.3.5)。 -结束   音符]

因此,正如您所提到的,函数参数包必须是最后一个参数 不幸的是,
类模板的非模板成员函数是普通函数 当它被实例化时(完全专业化)。 所以我希望这个问题中的代码可以逻辑地编译,如同 特例。