咱們先回憶一下,標準庫提供的算法的一些特徵:html
參數通常包括iterator。c++
要根據iterator的種類,和iterator包裝的元素的類型等信息,來決定使用最優化的算法。算法
好比若是是vector的iterator,那麼就能夠使用+,-操做;微信
若是是list的iterator,那麼就不能夠使用+,-操做。dom
因此,算法必須知道一些關於iterator的信息。學習
有一些容器對應的iterator是個類,因此在這個類裏,定義了以下的信息:優化
template<typename T> struct __list_iterator { typedef bidirectional_iterator_tag iterator_category; typedef T value_type; typedef T* pointer; typedef T& reference; typedef ptrdiff_t difference_type;
有了上面定義的定義,算法就可以知道iterator的信息了,算法就能夠正常工做了。到這裏位置貌似沒有traits什麼事,指針
加一箇中間層,也就是建立一個iterator_traits類,它包裝了iterator,並使用模板局部特化技術,來解決上面的問題。code
traits是萃取機的意思,也就是萃取iterator裏的信息,並給到算法。htm
traits技術:
//使用iterator提供的信息 template<typename Iterator> struct iterator_traits { typedef typename Iterator::iterator_category iterator_category; typedef typename Iterator::value_type value_typep; typedef typename Iterator::difference_type difference_type; typedef typename Iterator::pointer pointer; typedef typename Iterator::reference reference; }; //因爲沒法使用iterator的信息,因此traits本身提供了。 //局部特化,c++內置指針。 template<typename 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; }; //因爲沒法使用iterator的信息,因此traits本身提供了。 //局部特化,c++內置指針。 template<typename T> struct iterator_traits<const T *> { typedef random_access_iterator_tag iterator_category; typedef T value_type;//注意這裏不是const T;若是是const T,算法拿到這個類型,用這個類型定義變量後,卻沒法改變其值,那就沒有做用了,因此是T。 typedef ptrdiff_t difference_type; typedef const T* pointer; typedef const T& reference; };
算法向iterator_traits類要它須要的信息,iterator_traits再向iterator要,若是要到了,就使用;若是沒有要到就使用iterator_traits提供的。
算法舉例:list類的size方法。
size_type size() const { size_type result = 0; distance(begin(), end(), result); return result; //return distance(begin(), end()); } 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 <class InputIterator, class Distance> inline void __distance(InputIterator first, InputIterator last, Distance& n, input_iterator_tag) { while (first != last) { ++first; ++n; } } template <class RandomAccessIterator, class Distance> inline void __distance(RandomAccessIterator first, RandomAccessIterator last, Distance& n, random_access_iterator_tag) { n += last - first; } template <class Iterator> inline typename iterator_traits<Iterator>::iterator_category iterator_category(const Iterator&) { typedef typename iterator_traits<Iterator>::iterator_category category;//--① return category(); } template <class InputIterator, class Distance> inline void distance(InputIterator first, InputIterator last, Distance& n) { __distance(first, last, n, iterator_category(first)); }
代碼解說:在①處,算法向iterator_traits要iterator_category的信息,若是iterator能提供,就使用iterator裏的iterator_category,若是iterator不能提供,就使用iterator_traits裏的iterator_category。獲得iterator_category後,就能夠在編譯階段肯定調用哪個__distance方法了。
注意:是在編譯階段就能夠肯定,比在運行階段肯定調用哪一個__distance方法的效率要高。
下面代碼是沒有trais技術,是在運行階段才能肯定調用哪一個__distance方法。
template <class Iterator> void distance(Iterator& i){ if(is_random_access_iterator(i)){ __distance1(); } if(is_bidirectional_iterator(i)){ __distance2(); } }
標準庫的iterator_traits類,定義在stl_iterator.h文件裏。