STL运用的C++技术(2)——模板特化 .

来源:互联网 发布:300m网络 用哪几根线 编辑:程序博客网 时间:2024/05/14 14:37
 STL是C++标准库的重要组成部分之一,它不仅是一个可复用的组件库,更是一个包含算法与数据结构的软件框架,同时也是C++泛型编程的很好例子。STL中运用了许多C++的高级技术。本文介绍模板特化技术的运用。主要参考了《C++ Primer》和《STL源码剖析》。

       STL中大量运用了模块,可以说模板是创建类或函数的公式。但是,我们并不总能写出对所有可能被实例化的类型都最合适的模板。举个函数模板特化的例子。

[cpp] view plaincopyprint?
  1. template <typename T>  
  2. int Compare(const T &x, const T &y)  
  3. {  
  4.     if(x < y)  
  5.         return -1;  
  6.     else if(x > y)  
  7.         return 1;  
  8.     else  
  9.         return 0;  
  10. }  
         对于上面这个函数模板,如果用两个字符串指针来调用,那么比较的是指针值,也就是比较地址大小,而不是字符串的大小。因此为了能够将Compare函数用于字符串,就需要提供一个知道怎么比较C风格字符串的特殊定义。这就是模板特化。

        模板特化(template specialization)的定义为指定一个或多个模板形参的实际类型或实际值。例如可以为Compare模板函数定义一个特化版本。

[cpp] view plaincopyprint?
  1. template <> //template关键字后面接空括号  
  2. int Compare(const char * const &x, const char * const &y) //形参为指向常量的常指针的引用  
  3. {  
  4.     return strcmp(x, y);  
  5. }  
        上文简单阐述了模板特化,现在介绍模板特化在STL中的运用,以迭代器中的运用为例。

        迭代器是STL的关键所在,它将原本分开的数据容器和算法很好的胶合在一起。比如下面这个STL中的函数(摘自源码),命名上做了修改,同时略去了一些代码,但是足以说明问题。这个函数通过迭代器交换容器的数据,迭代器是数据容器和算法的桥梁,算法通过数据容器的迭代器访问容器中的数据,而不需关心容器的具体构造。

[cpp] view plaincopyprint?
  1. //真正的交换函数,内部调用   
  2. template <class Iter1, class Iter2, class T>  
  3. inline void _iter_swap(Iter1 a, Iter2 b, T) {  
  4.   T tmp = *a;  
  5.   *a = *b;  
  6.   *b = tmp;  
  7. }  
  8. //交换两个迭代器所指的元素,外部接口   
  9. template <class Iter1, class Iter2>  
  10. inline void iter_swap(Iter1 a, Iter2 b) {  
  11.  _iter_swap(a, b, VALUE_TYPE(Iter1)); //VALUE_TYPE返回迭代器的值类型  
  12. }  
       上面用到了一个VALUE_TYPE调用,注释说是返回迭代器的值类型,具体如何下文会有介绍。举这个例子,就是为了引出这个调用。本文讲的是模板特化,但是到这里好像已经跑题了,不知所云。铺垫差不多了,进入正题。

       问一个问题,iter_swap这个函数的形参是迭代器,我们需要在函数内部定义一个临时变量,变量的数据类型为迭代器所指的数据类型。那么我们如何知道迭代器所指的数据类型呢?有人说,可以利用模板实参推断机制,解决这个问题。代码如下所示:

[cpp] view plaincopyprint?
  1. //真正的交换函数   
  2. template <class Iter1, class Iter2, class T>  
  3. inline void _iter_swap(Iter1 a, Iter2 b, T) {  
  4.   T tmp = *a;  
  5.   *a = *b;  
  6.   *b = tmp;  
  7. }  
  8. //交换两个迭代器所指的元素   
  9. template <class Iter1, class Iter2>  
  10. inline void iter_swap(Iter1 a, Iter2 b) {  
  11.  _iter_swap(a, b, *a); //模板实参推断  
  12. }  
        但是如果要推导函数的返回类型,模板实参推断机制就失效了。模板实参推断机制的具体内容,将在本系列(3)中介绍。继续上面的问题,本文用了一个称之为VALUE_TYPE的调用来获取的,它就像是一个萃取剂,萃取出迭代器所指的数据类型。那么它是如何实现的呢?答案就是内嵌型别。在STL中,大多数容器要求定义迭代器的内嵌型别,下面是 list 中的定义,已化简。
[cpp] view plaincopyprint?
  1. class MyAlloc{    
  2. };  
  3.   
  4. template<class T>  
  5. struct List_iterator{  
  6.   typedef T value_type;  //list 迭代器的内嵌型别  
  7.   ...  
  8. };  
  9.   
  10. template <class T, class Alloc = MyAlloc>  
  11. class list{  
  12. public:  
  13.   typedef List_iterator<T>  iterator;  //list迭代器  
  14.   ...  
  15. };  
        通过下面这种方式就可以萃取出 list 迭代器所指的数据类型。
[cpp] view plaincopyprint?
  1. template<class I>  
  2. struct Iterator_traits{ //萃取剂定义  
  3.     typedef typename I::value_type value_type;  
  4. };  
  5.   
  6. Iterator_traits<list<int>::iterator>::value_type x = 1;  
        这种方式只能萃取出定义了内嵌型别的迭代器,但是如果是原生指针呢,它是没有内嵌型别的?比如 vector 容器,它是用原生指针做迭代器的。定义如下:
[cpp] view plaincopyprint?
  1. class MyAlloc{    
  2. };  
  3.   
  4. template <class T, class Alloc = MyAlloc>  
  5. class vector :   
  6. {  
  7. public:  
  8.   typedef T value_type;    //内嵌型别  
  9.   typedef value_type* pointer;  
  10.   typedef const value_type* const_pointer;  
  11.   typedef value_type* iterator;  //vector 迭代器,是原生指针  
  12.   typedef const value_type* const_iterator;  
  13.   typedef value_type& reference;  
  14.   typedef const value_type& const_reference;  
  15.   ...  
  16. };  
      模板特化终于登场了,下面加入了原生指针的支持,使用的正是模板特化技术,在泛化设计中加入了特化版本。该技术也是STL中的核心关键所在。
[cpp] view plaincopyprint?
  1. template<class I>  
  2. struct Iterator_traits{  
  3.     typedef typename I::value_type value_type;  
  4. };  
  5. //特化 原生指针   
  6. template<class T>  
  7. struct Iterator_traits<T*>{  
  8.     typedef T value_type;  
  9. };  
  10. //特化 原生常指针   
  11. template<class T>  
  12. struct Iterator_traits<const T*>{  
  13.     typedef T value_type;  
  14. };  
    下面给出了完整的代码,已在VS2008下测试通过。
[cpp] view plaincopyprint?
  1. #include <iostream>   
  2. #include <vector>   
  3. #include <list>   
  4. using namespace std;  
  5.   
  6. //萃取剂   
  7. template<class I>  
  8. struct Iterator_traits{  
  9.     typedef typename I::value_type value_type;  
  10. };  
  11. //特化 原生指针   
  12. template<class T>  
  13. struct Iterator_traits<T*>{  
  14.     typedef T value_type;  
  15. };  
  16. //特化 原生常指针   
  17. template<class T>  
  18. struct Iterator_traits<const T*>{  
  19.     typedef T value_type;  
  20. };  
  21.   
  22. #define VALUE_TYPE(I) Iterator_traits<I>::value_type()  
  23.   
  24. //交换两个迭代器所指的元素   
  25. template <class Iter1, class Iter2>  
  26. inline void iter_swap(Iter1 a, Iter2 b) {  
  27.  _iter_swap(a, b, VALUE_TYPE(Iter1)); //VALUE_TYPE返回迭代器的值类型  
  28. }  
  29. //真正的交换函数   
  30. template <class Iter1, class Iter2, class T>  
  31. inline void _iter_swap(Iter1 a, Iter2 b, T) {  
  32.   T tmp = *a;  
  33.   *a = *b;  
  34.   *b = tmp;  
  35. }  
  36. //测试函数   
  37. int main()  
  38. {  
  39.     int a = 1, b = 2;  
  40.     iter_swap(&a,&b);  
  41.     cout<<a<<' '<<b<<endl;  //2 1  
  42.       
  43.     list<int> l;  
  44.     l.push_back(3);  
  45.     l.push_back(4);  
  46.     iter_swap(l.begin(),++l.begin());  
  47.     cout<<*(l.begin())<<' '<<*(++l.begin())<<endl; //4 3  
  48.   
  49.     Iterator_traits<int *>::value_type w = 5;       //特化  
  50.     Iterator_traits<const int*>::value_type  x = 6; //特化  
  51.         Iterator_traits<vector<int>::iterator>::value_type y = 7; //vector 容器  
  52.     Iterator_traits<list<int>::iterator>::value_type z = 8;   //list 容器  
  53.     cout<<w<<' '<<x<<' '<<y<<' '<<z<<endl; //5 6 7 8  
  54.     return 0;  
  55. }  
        本文介绍模板特化的同时,其实也介绍了STL迭代器实现的另一关键技术——内嵌型别。下文将介绍模板实参推断机制。
      本人享有博客文章的版权,转载请标明出处 http://blog.csdn.net/wuzhekai1985
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 违章扣了100多分怎么办 车子累计扣12分怎么办 起诉了对方不来怎么办 在监狱里被打伤了怎么办 初三要体检没去怎么办 羁押人在看守所没判刑怎么办? 在看守所关两年了还没有判刑怎么办 开麻将馆被拘留怎么办 拘留31天了我该怎么办 收到一封拘留信怎么办 存钱的收据掉了怎么办 行政拘留法制没有批的怎么办 别人起诉我我该怎么办 去钟落潭看守所送衣服要怎么办 长城宽带账号密码忘了怎么办 预约考试密码忘了怎么办 健康证预约号忘记怎么办啊 人在看守所七个月还没结果怎么办 起诉书和判决书丢了怎么办 进了看守所信用卡逾期怎么办 公安局审讯室监控影相被删除怎么办 关进看守所以前的工作怎么办 上海初中借读生学籍怎么办 外地货北京三环怎么办 谁买了小产权怎么办 狗在小区丢了怎么办 太原回迁房多余的房子怎么办 回迁房被开发商抵押怎么办 回迁房源多开发商扣房怎么办 蝈蝈叫晚上怕吵怎么办 蝈蝈总不停的叫怎么办 按揭房没拿房产证夫妻离婚怎么办 按揭房子房产证还没有到离婚怎么办 结婚7年离婚孩子怎么办 合伙经营KTV股东意见不合怎么办 合伙生意转让意见不合怎么办 租完房子后悔了怎么办 通过中介买房产生纠纷怎么办 天津公租房资格证到期怎么办 买大房子后悔了怎么办 公款私存了该怎么办