模板参数的专门化

Specialization of template template parameters

本文关键字:专门化 参数      更新时间:2023-10-16

这是前一个问题的后续问题(关于不同的主题)。下面的代码包含了Dehstil使用专门化的建议。

一个有模板模板参数的函数应该如何专门化?

下面的代码(其中两个专门化行没有编译)使问题具体化了。

#include <cassert>
template<typename S> struct PA1 {};
template<typename S> struct PA2 {};
template<typename S> struct PB  {};
template<typename S> struct PC  {};
template<typename S> struct A1 { typedef PA1<S> P; };
template<typename S> struct A2 { typedef PA2<S> P; };
template<typename S> struct B  { typedef PB <S> P; };
template<typename S> struct C  { typedef PC <S> P; };
template<typename S, template<typename> class T> char fn(typename T<S>::P);
template<typename S, template<typename> class T> char fn(typename T<S>::P)
{
    return 'a';
}
template<typename S> char fn<B<S> >(B<S>::P) {   return 'b';  }
template<typename S> char fn<C<S> >(C<S>::P) {   return 'c';  }
int main()
{
    PA1<int> pa1;
    PA2<int> pa2;
    PB<int>  pb;
    PC<int>  pc;
    assert( (fn<int, A1>(pa1)) == 'a' );
    assert( (fn<int, A2>(pa2)) == 'a' );
    assert( (fn<int, B>(pb)) == 'b' );
    assert( (fn<int, C>(pc)) == 'c' );
}

四个函数调用fn<…,…>()在调用时具有相同的签名是很重要的,因为它们本身将驻留在应用于四个类A1/A2/B/c的模板类中。

c++标准不允许函数模板的部分特化!

重载你的函数而不是专门化它们。

阅读为什么不特化函数模板的解释?

然后阅读为什么要重载而不是专门化:模板专门化和重载by Herb Sutter


如何在重载

时统一调用所有函数

编写一个类模板call并将其特化为:

template<class S, template<typename> class T>
struct call
{
    static char fn(typename T<S>::P &p)
    {
         return ::fn<S,T>(p);
    }
};
 
template<class S>
struct call<S,B>
{
    static char fn(typename B<S>::P &p)
    {
         return ::fn<S>(p);
    }
};
 
template<class S>
struct call<S,C>
{
    static char fn(typename C<S>::P &p)
    {
         return ::fn<S>(p);
    }
};

然后你可以使用这个类模板统一调用所有的函数:

assert( (call<int, A1>::fn(pa1)) == 'a' );
assert( (call<int, A2>::fn(pa2)) == 'a' );
assert( (call<int, B>::fn(pb)) == 'b' );
assert( (call<int, C>::fn(pc)) == 'c' );

查看在线演示:http://www.ideone.com/TISIT

还请注意ideone.com(上面的链接)完整解决方案中的重载函数模板

函数只能完全特化。使用函数重载:

template<typename S> char fn(typename B<S>::P) {   return 'b';  }
template<typename S> char fn(typename C<S>::P) {   return 'c';  }