模板显式、隐式实例化和(偏)特化、具体化的详细分析

最近看了<The C++ Programing Language>看到了模板的特化,突然想起来<C++ Primer>上说的显式具体化、隐式具体化、特化、偏特化、具体化等概念弄得头晕脑胀,我在网上了找了好多帖子,才把概念给理清楚。

      一下是我把再网上找的资料整理一下。

      看着这么多叫法,其实就是三种。

     1. 显示实例化

     2. 隐式实例化

     3. 特化(=具体化)、偏特化


一、实例化

1.显示、隐式实例化

      什么是实例化:一个通过使用具体值替换模板参数,从模板产生的普通类,函数或者成员函数的过程。

     显示实例化:通过名字可见,就是清楚的表明你要实例化的类型

     隐式实例化:通过编译器自己推测判断要实例化的类型。

    比如一个模板:

  1. template<class T> //函数模板实现  
  2. void swap(T &a, T &b)  
  3. {  
  4.     T temp;  
  5.     temp = a;  
  6.     a = b;  
  7.     b = temp;  
  8. }  

 a. 显示实例化

     template  void swap<int>();  // 无须给该函数重新编写函数体,这只是个声明

     为什么要显示实例化? 

     主要是提高效率,当显式实例化模板时,在使用模板之前,编译器根据显式实例化指定的类型生成模板实例,这样就相当于本程序里面有个一

  1. void swap(int &a, int &b)  
  2. {  
  3.    int temp;  
  4.    temp = a;  
  5.    a = b;  
  6.    b = temp;  
  7. }  
这样的话,每次需要调用 swap<int>(a,b)的时候每次都重新生成该类型的代码,可以节省空间,也能提高效率。这就是为什么要是显式的实例化的原因。

b. 隐式实例化

    隐式实例化指的是:在使用模板之前,编译器不生成模板的声明和定义实例。只有当使用模板时,编译器才根据模板定义生成相应类型的实例。

   int i=0, j=1;
   swap(i, j); //编译器根据参数i,j的类型隐式地生成swap<int>(int &a, int &b)的函数定义。

   隐式实例化就是程序员为了省事,把类型省略让编译器判断,这是一个偷懒的表现吧。


二、特化

1.  特化(=具体化)

     然而通常又有一些特殊的情况,不能直接使用泛型模板展开实现,这时就需要针对某个特殊的类型或者是某一类特殊的类型,而实现一个特例模板————即模板特化

    当T如果为 一个 struct类型的,它的交换就无法进行,所以我们针对这种特殊的情形,我们专门写了一个函数,只有当T为 这种struct类型时候,才会调用这个特化的函数

  1. //对函数  
  2. #define MAXNAME 128  
  3. struct job  
  4. {  
  5. char name[MAXNAME]:  
  6. int salary;  
  7. };  
  8.   
  9. template<class T>  
  10. void swap(T &a, T &b )  
  11. {  
  12.   T temp;  
  13.   temp = a;  
  14.   a = b;  
  15.   b = temp;  
  16. };  
  17.   
  18. template void swap<int>(int &a, int & b);  //显式实例化,只需声明  
  19.   
  20. template<> void swap<job>(job &a, job &b)   //显式具体化(上面已经讲过,注意与实例化区分开,必须有定义)  
  21. {  
  22.   int salary:  
  23.   salary = a.salary:  
  24.   a.salary = b.salary;  
  25.   b.salary = salary;  
  26. };//explicite specialization.  
  27.   
  28. //对类模板:  
  29. template <class T>  
  30. class Arrary  
  31. {  
  32. private:  
  33.   T* ar;  
  34.   int l;  
  35. ...  
  36. };//template class declaration.  
  37.   
  38. template class Array<int>;   //explicit instantiation. 显式实例化  
  39.   
  40. template<> class Array<job>  
  41. {  
  42. private:  
  43.   job* ar;  
  44.   int l;  
  45. };//expicit specialization.   显式具体化,类定义体可以不同于类模板Array  


2. 偏特化

    模板的偏特化是指需要根据模板的部分参数进行特化。

a. 类模板的偏特化

例如c++标准库中的类vector的定义

  1. template <class T, class Allocator>  
  2. class vector { // … // };  
  3. template <class Allocator>  
  4. class vector<bool, Allocator> { //…//};  
  5. //这个偏特化的例子中,一个参数被绑定到bool类型,而另一个参数仍需要由用户使用时指定。  
b. 函数模板的偏特化

网上看到有人说:从严格意义上讲,函数模板并不支持偏特化(我对这个不是很理解),但由于可以对函数进行重载,所以可以达到类似于类模板偏特化的效果。
比如:
a) template <class T> void f(T); 
    根据重载规则,对a)进行重载
b) template < class T> void f(T*); 
    如果将a)称为基模板,那么b)称为对基模板a)的重载,而非对a)的偏特化。
这里我就不深入的剖析偏特化了。

三、模板的匹配顺序

1. 类模板的匹配规则

例如:
template <class T> class vector{//…//}; // (a) 普通型
template class vector<typename> ; // (b) 的显式实例化
template <class T> class vector<T*>{//…//}; // (c) 对指针类型特化
template <> class vector <void*>{//…//}; // (d) 对void*进行特化
每个类型都可以用作普通型(a)的参数,但只有指针类型才能用作(b)的参数,而只有void*才能作为(c)的参数

所以,当一个调用一个模板类,首先,找显式实例化的,如果不匹配;接着,找特化的,然后,找偏特化的,最后,根据模板隐式实例化

2.函数模板的匹配规则

例如:

void swap(int &a, int &b){} // 普通的函数
template<> swap<int>(int &a, int &b){} // 特化的模板函数
template void swap<int>(int &a, int &b); // 显式实例化,这个只用声明就行
template<class T> void swap(T &a, T &b){} // 模板

以上书写的顺序就是模板的调用顺序。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值