c++迭代器和traits特性提取

来源:互联网 发布:算法设计 算法导论 编辑:程序博客网 时间:2024/06/05 10:26

转自:点击打开链接

一、迭代器的概念

迭代器是STL将数据容器和算法分开后连接的纽带,也是泛型思维发展的必然结果。泛型算法就是通过迭代器操作容器的,使得算法和容器本身分离开来。

迭代器模式:提供一种方式,可以依次访问一个聚合物(容器)中所有元素而不暴露聚合物内部的表达方式。

迭代器类似与智能指针,但是它一般不会对所指向的元素进行释放空间,因为迭代器只是在指针外面包裹一层外加一些操作。迭代器最重要编码工作是完成一些操作符的重载,这些重载都是针对指针类型的操作,例如,++,——,*,->等,不同类型的迭代器完成的功能都不相同,详解见下文。

迭代器定义的位置最好是在容器内,将定义的任务交给了容器的设计者,因为每一种容器都对应一种迭代器,而定义在内部也不会暴露容器的内部元素。

二、迭代器型别和trait编程

迭代器的型别主要有五种:value_type,catalog,reference,pointer,diffrence。分别代表这迭代器所指对象类型,迭代器类型,迭代器所指类型引用,迭代器所指类型指针,用什么类型表示迭代器之间距离(如int类型)。如何提取这些迭代器都有的特性呢?

首先,为所有的迭代器提供一个型别类型,每定义一个迭代器都必须继承该型别类型。

  1. template <class Category, class T, class Distance = ptrdiff_t,  
  2.           class Pointer = T*, class Reference = T&>  
  3. struct iterator {  
  4.   typedef Category  iterator_category;  
  5.   typedef T         value_type;  
  6.   typedef Distance  difference_type;  
  7.   typedef Pointer   pointer;  
  8.   typedef Reference reference;  
  9. };  

当定义迭代器的时候,必须给定迭代器的特性。STL为提取迭代器的特性,提供了一个模板类iterator_trait,适用于所有的迭代器和原生指针,定义如下

  1. template <class Iterator>  
  2. struct iterator_traits  
  3. {  
  4.   // 迭代器类型, STL提供五种迭代器  
  5.   typedef typename Iterator::iterator_category iterator_category;  
  6.   
  7.   // 迭代器所指对象的型别  
  8.   // 如果想与STL算法兼容, 那么在类内需要提供value_type定义  
  9.   typedef typename Iterator::value_type        value_type;  
  10.   
  11.   // 这个是用于处理两个迭代器间距离的类型  
  12.   typedef typename Iterator::difference_type   difference_type;  
  13.   
  14.   // 直接指向对象的原生指针类型  
  15.   typedef typename Iterator::pointer           pointer;  
  16.   
  17.   // 这个是对象的引用类型  
  18.   typedef typename Iterator::reference         reference;  
  19. };  
  20.   
  21. // 针对指针提供特化版本  
  22. template <class T>  
  23. struct iterator_traits<T*>  
  24. {  
  25.   typedef random_access_iterator_tag iterator_category;  
  26.   typedef T                          value_type;  
  27.   typedef ptrdiff_t                  difference_type;  
  28.   typedef T*                         pointer;  
  29.   typedef T&                         reference;  
  30. };  
  31.   
  32. // 针对指向常对象的指针提供特化  
  33. template <class T>  
  34. struct iterator_traits<const T*>  
  35. {  
  36.   typedef random_access_iterator_tag iterator_category;  
  37.   typedef T                          value_type;  
  38.   typedef ptrdiff_t                  difference_type;  
  39.   typedef const T*                   pointer;  
  40.   typedef const T&                   reference;  
  41. };  

指针并非类型,因此需要偏特化成一个模板对应指针的特性,可以看出,指针是随机访问迭代器类型。

迭代器的类型有五种:输入、输出、前向、双向、随机访问五种迭代器,输入和输出分别只读和只写,只能向前不能向后,前向迭代器可以进行读写,只能向前,双向迭代器可以向前和向后移动,但每次只能移动一次,随机访问迭代器可以跳跃移动,与原生指针操作相同。

STL中构建了这五种类别,用于标识迭代器的类别。

  1. // 用于标记迭代器类型  
  2. struct input_iterator_tag {};  
  3. struct output_iterator_tag {};  
  4. struct forward_iterator_tag : public input_iterator_tag {};  
  5. struct bidirectional_iterator_tag : public forward_iterator_tag {};  
  6. struct random_access_iterator_tag : public bidirectional_iterator_tag {};  

可以看出继承关系,使用template元编程技术,之所以使用结构体或类型,是为了进行参数推导,将判断在编译期执行而非运行期,因为每个迭代器操作不同,因此需要不同的函数版本对应不同迭代器。

三、_type_trait

以上讲的是迭代器的特性提取,还有类型的特性提取。类型的型别主要有五种:has_trivial_default_constructor、has_trivial_copy_constructor、has_trivial_assignment_operator、has_trivial_destructor、is_POD_type。

STL提供的模板_type_trait类

  1. template <class type>  
  2. struct __type_traits  
  3. {  
  4.     // 不要移除这个成员  
  5.     // 它通知能自动特化__type_traits的编译器, 现在这个__type_traits template是特化的  
  6.     // 这是为了确保万一编译器使用了__type_traits而与此处无任何关联的模板时  
  7.     // 一切也能顺利运作  
  8.    typedef __true_type     this_dummy_member_must_be_first;  
  9.   
  10.    // 以下条款应当被遵守, 因为编译器有可能自动生成类型的特化版本  
  11.    //   - 你可以重新安排的成员次序  
  12.    //   - 你可以移除你想移除的成员  
  13.    //   - 一定不可以修改下列成员名称, 却没有修改编译器中的相应名称  
  14.    //   - 新加入的成员被当作一般成员, 除非编译器提供特殊支持  
  15.   
  16.    typedef __false_type    has_trivial_default_constructor;  
  17.    typedef __false_type    has_trivial_copy_constructor;  
  18.    typedef __false_type    has_trivial_assignment_operator;  
  19.    typedef __false_type    has_trivial_destructor;  
  20.    typedef __false_type    is_POD_type;  
  21. };  

_true_type和_false_type是结构体,用于标记真假,也是为了用于参数推导才使用类型的。STL对每个内置类型均进行了特化,且将所有型别标记为_true_type

指针不是类型,但是有此五种特性,进行偏特化

  1. template <class T>  
  2. struct __type_traits<T*>  
  3. {  
  4.    typedef __true_type    has_trivial_default_constructor;  
  5.    typedef __true_type    has_trivial_copy_constructor;  
  6.    typedef __true_type    has_trivial_assignment_operator;  
  7.    typedef __true_type    has_trivial_destructor;  
  8.    typedef __true_type    is_POD_type;  
  9. };  

对于某些类型的指针可能有不同的型别,可以进行特化。

每种新定义的类型,都需要进行特化标识自己的特性,否则按照默认的全部为_false_type。



iterator_traits的用法

转自:点击打开链接

MSDN上看到的原型:

[cpp] view plain copy
  1. template<class Iterator>  
  2.    struct iterator_traits {  
  3.    typedef typename Iterator::iterator_category iterator_category;  
  4.    typedef typename Iterator::value_type value_type;  
  5.    typedef typename Iterator::difference_type difference_type;  
  6.    typedef typename Iterator::pointer pointer;  
  7.    typedef typename Iterator::reference reference;  
  8.    };  
  9. template<class Type>  
  10.    struct iterator_traits<Type*> {  
  11.    typedef random_access_iterator_tag iterator_category;  
  12.    typedef Type value_type;  
  13.    typedef ptrdiff_t difference_type;  
  14.    typedef Type *pointer;  
  15.    typedef Type& reference;  
  16.    };  
  17. template<class Type>  
  18.    struct iterator_traits<const Type*> {  
  19.    typedef random_access_iterator_tag iterator_category;  
  20.    typedef Type value_type;  
  21.    typedef ptrdiff_t difference_type;  
  22.    typedef const Type *pointer;  
  23.    typedef const Type& reference;  
  24.    };  

就是说模板参数可以是一个迭代器,也可以是一个具体数据类型的指针。

如下例子:

首先是执行插入排序的一个函数:

[cpp] view plain copy
  1. template<typename Iterator>  
  2. void insertionSort(const Iterator &a,const Iterator &b){  
  3.     typedef typename iterator_traits<Iterator>::value_type T;  
  4.     int i,j,n=distance(a,b);  
  5.     T key;  
  6.     Iterator p,q,t;  
  7.     for(j=1,q=p=a,p++,t=p;j<n;j++,q=p,p++,t=p){  
  8.         key=*p;  
  9.         i=j-1;  
  10.         while(i>=0 && *q>key){  
  11.             *t=*q;  
  12.             i--,t--,q--;  
  13.         }  
  14.         *t=key;  
  15.     }  
  16. }  

main函数:

[cpp] view plain copy
  1. #include <iostream>  
  2. #include <string>  
  3. #include <vector>  
  4. #include <list>  
  5. #include <iterator>  
  6. #include "insertionsort_cpp.h"  
  7. using namespace std;  
  8. int main(int argc,char** argv)  
  9. {  
  10.     int a[]={5,1,9,4,6,2,0,3,8,7},i;  
  11.     string b[]={"ChonqQing","ShangHai","AoMen","TianJin","BeiJing","XiangGang"};  
  12.     double c[]={8.5,6.3,1.7,9.2,0.5,2.3,4.1,7.4,5.9,3.7};  
  13.         vector<string> vb=vector<string>(b,b+6);  
  14.     list<double> lc=list<double>(c,c+10);  
  15.     insertionSort<int*>(a,a+10);    //模板参数为具体类型的指针  
  16.     copy(a,a+10,ostream_iterator<int>(cout," "));  
  17.     cout<<endl;  
  18.     insertionSort<vector<string>::iterator>(vb.begin(),vb.end()); //模板参数为一个迭代器  
  19.     copy(vb.begin(),vb.end(),ostream_iterator<string>(cout," "));  
  20.     cout<<endl;  
  21.     insertionSort<list<double>::iterator>(lc.begin(),lc.end());  
  22.     copy(lc.begin(),lc.end(),ostream_iterator<double>(cout," "));  
  23.     cout<<endl;  
  24.     return(0);  
  25. }  

0 0
原创粉丝点击