学科分类
目录
C++基础

模板特化

学习模板特化之前,我们先了解什么是特化,所谓特化就是将泛型的东西具体化。模板特化就是为已有的模板参数进行一些使其特殊化的指定,使得以前不受任何约束的模板参数,受到特定约束或完全被指定下来。

也许读者会想既然都确定下来了那定义模板还有何意义呢,很多时候我们既需要一个模板能应对各种情景,又需要它的某个特定的类型(比如bool)来进行特别的处理,这种情形下就需要对模板进行特化。模板特化可分为偏特化与全特化,本节我们就来学习一下这两种特化形式。

1、偏特化

偏特化就是模板中的模板参数没有被全部确定,需要编译器在编译时进行确定。例如定义一个类模板,如下所示:

template<typename T, typename U>
class A
{
  //……
};

将其中一个模板形参特化为int类型,如下所示:

template<typename T>
class A<T, int>
{
  //……
};

这就是偏特化的典型例子,一个参数被绑定到int类型,另一个参数由用户指定。

2、全特化

全特化就是模板中的模板参数全部被指定为确定的类型,其标志就是产生出完全确定的东西。例如有类模板定义,如下所示:

template<class T>
class Compare
 {
 public:
   bool IsEqual(const T& lh, const T& rh)
   {
​     return lh == rh;
   }
 };

将其特化为对float类型数据的比较,定义如下所示:

template<>
class Compare<float>
 {
 public:
   bool IsEqual(const float& lh, const float& rh)
   {
​     return abs(lh - rh) < 10e-3;
   }
 };

上述定义中template<>就是告诉编译器这是一个特化的模板,模板特化之后就可以处理特殊情况。

接下来我们通过一个案例来演示类模板与函数模板特化的使用,具体如例1所示。

例1

 1    #include <iostream>
 2    using namespace std;
 3    //定义函数模板
 4    template<typename T>
 5    bool IsEqual(T t1, T t2)
 6    {
 7            return t1 == t2;
 8    }
 9    //函数模板的特化
 10    template<>
 11    bool IsEqual(char* s1, char* s2)
 12    {
 13            return strcmp(s1, s2) == 0;
 14    }
 15    //类模板
 16    template<typename T>
 17    class Compare
 18    {
 19    public:
 20            bool IsEqual(T t1, T t2)
 21            {
 22                return t1 == t2;
 23            }
 24    };
 25    //类模板特化
 26    template<>
 27    class Compare<char*>
 28    {
 29    public:
 30            bool IsEqual(char* s1, char* s2)
 31            {
 32                return strcmp(s1, s2) == 0;
 33            }
 34    };
 35    int main()
 36    {
 37            char str1[] = "abc";
 38            char str2[] = "abc";
 39            cout << "函数模板和函数模板特化" << endl;
 40            cout << IsEqual(1, 3) << endl;  //调用函数模板
 41            cout << IsEqual(str1, str2) << endl;  //调用特化的函数模板
 42            Compare<int> c1;
 43            Compare<char*> c2;
 44            cout << "类模板和类模板特化" << endl;
 45            cout << c1.IsEqual(1.2, 3.4) << endl; //调用类模板
 46            cout << c2.IsEqual(str1, str2) << endl; //调用特化的类模板
 47            system("pause");
 48            return 0;
 49    }

运行结果如图1所示。

图1 例1运行结果

例1中分别定义了相同功能的函数模板和类模板,然后将两种模板都特化为char类型,当用1、3变量调用时,都是调用的模板,当传入char类型的str1与str2时,都调用了特化了的模板。

在上述所讲的特化与偏特化中,都是将模板特化为绝对类型,除此之外,还可以将模板特化为引用、指针类型与模板类型,例如将例1中的类模板Compare特化为指针类型,代码如下所示:

template<typename T>
class Compare<T*>
{
public:
  bool IsEqual(const T* pT1, const T* pT2)
  {
​    return Compare<T>::IsEqual(*pT1, *pT2);
  }
};

这种特化其实不是一种绝对的特化,它只是对类型做了某些限定,但仍然保留了其一定的模板性,这种特化给我们提供了极大的便利,如这里,我们无需对int、float等类型再分别做特化了。

还可以将其特化为另一个类模板,代码如下所示:

template<class T>
class Compare
{
public:
  bool IsEqual(const vector<T>& lh, const vector<T>& rh)
  {
​    if (lh.size() != rh.size()) 
        return false;
​    else
​    {
​      for (int i = 0; i < lh.size(); ++i)
​      {
​        if (lh[i] != rh[i]) return false;
​      }
​    }
​    return true;
  }
};

这就把IsEqual的参数限定为一种vector类型, 但具体是vector<int>还是vector<float>, 我们可以不关心, 因为对于这两种类型,我们的处理方式是一样的,把这种方式称为“半特化”。

关于模板,需要读者多加实践才能真正掌握其要领,体会到它给我们带来的极大方便,C++中的标准模板库就是基于模板来完成的,理解掌握好模板也能为学习STL打下坚实的基础。

点击此处
隐藏目录