c++迭代器和traits特性提取
轉自:點選開啟連結
一、迭代器的概念
迭代器是STL將資料容器和演算法分開後連線的紐帶,也是泛型思維發展的必然結果。泛型演算法就是通過迭代器操作容器的,使得演算法和容器本身分離開來。
迭代器模式:提供一種方式,可以依次訪問一個聚合物(容器)中所有元素而不暴露聚合物內部的表達方式。
迭代器類似與智慧指標,但是它一般不會對所指向的元素進行釋放空間,因為迭代器只是在指標外面包裹一層外加一些操作。迭代器最重要編碼工作是完成一些操作符的過載,這些過載都是針對指標型別的操作,例如,++,——,*,->等,不同型別的迭代器完成的功能都不相同,詳解見下文。
迭代器定義的位置最好是在容器內
二、迭代器型別和trait程式設計
迭代器的型別主要有五種:value_type,catalog,reference,pointer,diffrence。分別代表這迭代器所指物件型別,迭代器型別,迭代器所指型別引用,迭代器所指型別指標,用什麼型別表示迭代器之間距離(如int型別)。如何提取這些迭代器都有的特性呢?
首先,為所有的迭代器提供一個型別型別,每定義一個迭代器都必須繼承該型別型別。
- template <class Category,
- class Pointer = T*, class Reference = T&>
- struct iterator {
- typedef Category iterator_category;
- typedef T value_type;
- typedef Distance difference_type;
- typedef Pointer pointer;
- typedef Reference reference;
- };
當定義迭代器的時候,必須給定迭代器的特性。STL為提取迭代器的特性,提供了一個模板類iterator_trait,適用於所有的迭代器和原生指標,定義如下
- template <class Iterator>
- struct iterator_traits
- {
- // 迭代器型別, STL提供五種迭代器
- typedef typename Iterator::iterator_category iterator_category;
- // 迭代器所指物件的型別
- // 如果想與STL演算法相容, 那麼在類內需要提供value_type定義
- typedef typename Iterator::value_type value_type;
- // 這個是用於處理兩個迭代器間距離的型別
- typedef typename Iterator::difference_type difference_type;
- // 直接指向物件的原生指標型別
- typedef typename Iterator::pointer pointer;
- // 這個是物件的引用型別
- typedef typename Iterator::reference reference;
- };
- // 針對指標提供特化版本
- template <class T>
- struct iterator_traits<T*>
- {
- typedef random_access_iterator_tag iterator_category;
- typedef T value_type;
- typedef ptrdiff_t difference_type;
- typedef T* pointer;
- typedef T& reference;
- };
- // 針對指向常物件的指標提供特化
- template <class T>
- struct iterator_traits<const T*>
- {
- typedef random_access_iterator_tag iterator_category;
- typedef T value_type;
- typedef ptrdiff_t difference_type;
- typedef const T* pointer;
- typedef const T& reference;
- };
指標並非型別,因此需要偏特化成一個模板對應指標的特性,可以看出,指標是隨機訪問迭代器型別。
迭代器的型別有五種:輸入、輸出、前向、雙向、隨機訪問五種迭代器,輸入和輸出分別只讀和只寫,只能向前不能向後,前向迭代器可以進行讀寫,只能向前,雙向迭代器可以向前和向後移動,但每次只能移動一次,隨機訪問迭代器可以跳躍移動,與原生指標操作相同。
STL中構建了這五種類別,用於標識迭代器的類別。
- // 用於標記迭代器型別
- struct input_iterator_tag {};
- struct output_iterator_tag {};
- struct forward_iterator_tag : public input_iterator_tag {};
- struct bidirectional_iterator_tag : public forward_iterator_tag {};
- 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類
- template <class type>
- struct __type_traits
- {
- // 不要移除這個成員
- // 它通知能自動特化__type_traits的編譯器, 現在這個__type_traits template是特化的
- // 這是為了確保萬一編譯器使用了__type_traits而與此處無任何關聯的模板時
- // 一切也能順利運作
- typedef __true_type this_dummy_member_must_be_first;
- // 以下條款應當被遵守, 因為編譯器有可能自動生成型別的特化版本
- // - 你可以重新安排的成員次序
- // - 你可以移除你想移除的成員
- // - 一定不可以修改下列成員名稱, 卻沒有修改編譯器中的相應名稱
- // - 新加入的成員被當作一般成員, 除非編譯器提供特殊支援
- typedef __false_type has_trivial_default_constructor;
- typedef __false_type has_trivial_copy_constructor;
- typedef __false_type has_trivial_assignment_operator;
- typedef __false_type has_trivial_destructor;
- typedef __false_type is_POD_type;
- };
_true_type和_false_type是結構體,用於標記真假,也是為了用於引數推導才使用型別的。STL對每個內建型別均進行了特化,且將所有型別標記為_true_type
指標不是型別,但是有此五種特性,進行偏特化
- template <class T>
- struct __type_traits<T*>
- {
- typedef __true_type has_trivial_default_constructor;
- typedef __true_type has_trivial_copy_constructor;
- typedef __true_type has_trivial_assignment_operator;
- typedef __true_type has_trivial_destructor;
- typedef __true_type is_POD_type;
- };
對於某些型別的指標可能有不同的型別,可以進行特化。
每種新定義的型別,都需要進行特化標識自己的特性,否則按照預設的全部為_false_type。
iterator_traits的用法
轉自:點選開啟連結
MSDN上看到的原型:
[cpp] view plain copy- template<class Iterator>
- struct iterator_traits {
- typedef typename Iterator::iterator_category iterator_category;
- typedef typename Iterator::value_type value_type;
- typedef typename Iterator::difference_type difference_type;
- typedef typename Iterator::pointer pointer;
- typedef typename Iterator::reference reference;
- };
- template<class Type>
- struct iterator_traits<Type*> {
- typedef random_access_iterator_tag iterator_category;
- typedef Type value_type;
- typedef ptrdiff_t difference_type;
- typedef Type *pointer;
- typedef Type& reference;
- };
- template<class Type>
- struct iterator_traits<const Type*> {
- typedef random_access_iterator_tag iterator_category;
- typedef Type value_type;
- typedef ptrdiff_t difference_type;
- typedef const Type *pointer;
- typedef const Type& reference;
- };
就是說模板引數可以是一個迭代器,也可以是一個具體資料型別的指標。
如下例子:
首先是執行插入排序的一個函式:
[cpp] view plain copy- template<typename Iterator>
- void insertionSort(const Iterator &a,const Iterator &b){
- typedef typename iterator_traits<Iterator>::value_type T;
- int i,j,n=distance(a,b);
- T key;
- Iterator p,q,t;
- for(j=1,q=p=a,p++,t=p;j<n;j++,q=p,p++,t=p){
- key=*p;
- i=j-1;
- while(i>=0 && *q>key){
- *t=*q;
- i--,t--,q--;
- }
- *t=key;
- }
- }
main函式: [cpp] view plain copy
- #include <iostream>
- #include <string>
- #include <vector>
- #include <list>
- #include <iterator>
- #include "insertionsort_cpp.h"
- using namespace std;
- int main(int argc,char** argv)
- {
- int a[]={5,1,9,4,6,2,0,3,8,7},i;
- string b[]={"ChonqQing","ShangHai","AoMen","TianJin","BeiJing","XiangGang"};
- double c[]={8.5,6.3,1.7,9.2,0.5,2.3,4.1,7.4,5.9,3.7};
- vector<string> vb=vector<string>(b,b+6);
- list<double> lc=list<double>(c,c+10);
- insertionSort<int*>(a,a+10); //模板引數為具體型別的指標
- copy(a,a+10,ostream_iterator<int>(cout," "));
- cout<<endl;
- insertionSort<vector<string>::iterator>(vb.begin(),vb.end()); //模板引數為一個迭代器
- copy(vb.begin(),vb.end(),ostream_iterator<string>(cout," "));
- cout<<endl;
- insertionSort<list<double>::iterator>(lc.begin(),lc.end());
- copy(lc.begin(),lc.end(),ostream_iterator<double>(cout," "));
- cout<<endl;
- return(0);
- }