Design Pattern中對迭代器的模式定義:提供一種方法能都依序訪問某個聚合物(容器)內所含的各個元素,而又無需暴露該聚合物的內部表述方式。
迭代器是一種相似指針對象,最重要的工做是進行operator*和operator->進行重載,除此以外還有++,==,=這一系列運算符的重載,不可避免地曝光了不少結構的實現細節。因此將迭代器的開發任務交給結構的設計者更加高效。算法
如何獲取「迭代器所指對象」的類型?解決辦法是使用模板函數參數推導機制。dom
//簡單舉例 template <class I, class T> void func_impl(I iter,T e) { //T就是迭代器所指之物的類型 。。。 } template <class I> void func(I iter) {//對外接口 func_impl(iter,*iter);//實際工做 }
若是value type要用於函數傳回值,使用參數推導就沒有做用了,能夠經過聲明內嵌類型解決。函數
template <class T> struct Iter { typedef T value_type;//內嵌類型 ... }; template <calss I> typename I:value_type func(I iter) { //typename 關鍵字告訴編譯器 value_type表明一個類型 ... }//返回類型I:value_type
這種方法僅限於定義了內嵌類型的class type成員,對於原生指針類型,沒法定義內嵌類型。因而引入template partial sepcilization(模板偏特化),即若是class template擁有多個template參數,能夠針對一部分參數進行特化,至關於在泛化設計中提供一個特化版本。設計
template <typename T> class C<T*> {}; //T*爲原生指針就是T爲任何類型的進一步條件限制。 template <class I> struct iterator_traits { typedef typename I::value_type value_type; };//若是I定義了 本身的value_type,能夠萃取出value_type;
多了一層間接性能夠擁有特化版本:指針
template <class T> struct iterator_traits<T*> { typedef T value_type; }//原生指針如int*類型也能夠萃取出value_type; //可是針對指向常數對象的指針,iterator_traits<const int*>::value_type,獲取類型是const int,可使用另外一種特化 template <class T> struct iterator_traits<const T*> { typedef T value_type;//類型爲T,而非const T };
根據經驗,最經常使用到的五種關聯類型:value_type,difference type,pointer,reference,iterator category。
value type:迭代器所指對象的類型;code
difference type:兩迭代器之間的距離對象
template <class I,calss T> typename iterator_traits::difference_type count(I first,I last,const value &value) { typename iterator_traits::difference_type n = 0; for(;first !=last;++first) if(*first == value) ++n; return n; } //針對原生指針,使用內建類型prtdiff_t template <class T> struct iterator_traits<T*> { typedef prtdiff_t difference_type; };
reference type:迭代器所指對象內容是否容許改變,分爲constant iterators和mutable iterators,後者應當返回左值,在C++中使用reference方式返回左值。若是mutable iterator p的value type是T,*p類型是T&。blog
pointer type:reference type返回左值表明p所指內容,而pointer type返回左值表明p所指以內容的地址。繼承
iterator_category:首先討論迭代器的分類接口
直線與箭頭表明概念與強化關係,若是算法接收一種迭代器,那麼就能夠接受強化類型的迭代器。設計算法時,儘可能針對某種迭代器提供明肯定義,針對強化迭代器提供另外一種定義,才能提供最大效率。任何迭代器屬於其所類型中最強的那個。
爲了實現針對不一樣類型迭代器的重載函數,traits應該能萃取出迭代器的類型,以做爲算法的參數之一。
42 struct input_iterator_tag {}; 43 struct output_iterator_tag {}; 44 struct forward_iterator_tag : public input_iterator_tag {}; 45 struct bidirectional_iterator_tag : public forward_iterator_tag {}; 46 struct random_access_iterator_tag : public bidirectional_iterator_tag {}; //Input版,模板以算法所能接受的最低階迭代器類型做爲形參 tempalte <class InputIterator,class Distance> inline void __advance(InputIterator &i,Distance n,input_iterator_tag) { while(n--) ++i; } // Forward版,傳遞調用Input版 tempalte <class ForwardIterator,class Distance> inline void __advance(ForwardIterator &i,Distance n,forward_iterator_tag) { __advance(i,n,input_iterator_tag()); } //Bidirectional版支持兩個方向 tempalte <class BidirectionalIterator,class Distance> inline void __advance(BidirectionalIterator &i,Distance n,bidirectional_iterator_tag) { if(n >= 0) while(n--) ++i; else while(n++) --i; } //Random Access版 tempalte <class RandomAccessIterator,class Distance> inline void __advance(RandomAccessIterator &i,Distance n,random_access_iterator_tag) { i+=n; }
最後一個參數用於聲明類型,激活重載,並不使用該參數。
//提供上層接口,最後一個參數產生臨時對象,在編譯時決定調用那個__advance tempalte <class InputIterator,class Distance> inline void advance(InputIterator &i,Distance n) { __advance(i,n,iterator_traits<InputIterator>::iterator_category()); } //定義iterator_category()以下: template <class I> inline typename iterator_traits<I>::iterator_category iterator_category(const &i) { typedef typename iterator_traits<I>::iterator_category category; reutrn category(); } //對於原生指針類型的iterator_category(),是一種RandomAccessIterator template <class T> struct iterator_traits<T*> { typedef rendom_access_iterator_tag iterator_category; }
使用struct繼承方式來定義分類標籤,有助於消除「單純傳遞調用函數」。好比前面的advance()的ForwardIterator版,能夠不用寫,編譯器會調用其父類函數(Input版)。(todo:對OutputIterator定位不明朗,forward_tag並無繼承output_tag)
至此,itarator_traits結構包含如下部分:
tempalte <class I> struct iterator_traits { typedef typename I::value_type value_type; typedef typename I::iterator_category iterator_category; typedef typename I::differnce_type difference_type; typedef typename I::pointer pointer; typedef typename I::reference reference; };
tempalte <class Catagory,class T,class Distance = ptrdiff_t,class Pointer = T*,class Reference = &T> struct iterator { typedef Category iterator_category; typedef T value_type; typedef Disatnce difference_type; typedef Pointer pointer; typedef Reference reference; }; //iterator不包含數據,繼承時不會有額外開銷,通常只需提供前兩個參數。 tempalte <class Item> struct ListIterator:public std::iterator<std::forward_iterator_tag,Item> { ... }
迭代器的做用是設計適當的關聯類型;設計適當的迭代器是容器的責任。而算法則獨立於迭代器和容器。
__type_traits<T>::has_trivial_default_constructor __type_traits<T>::has_trivial_copy_constructor __type_traits<T>::has_trivial_assignment_operator __type_traits<T>::has_trivial_destructor __type_traits<T>::is_POD_type struct __true_type {}; struct __false_type {};