標籤:++ 操作 減法 選擇 out 版本 nbsp str false
在STL中,容器跟演算法是分開設計的,演算法是通過迭代器來對容器進行操作的。
在演算法運用迭代器的時候,可能會用到其相應的型別,例如傳回值為容器中元素的型別,又或者說根據迭代器的類型來選擇更好的演算法等等。
為了實現這一點,還有為了相容內建型別的迭代器(vector迭代器直接使用原生pointer),STL使用了traits技法,用於提取迭代器的特性(相應的型別)。
1.首先在iterator中typedef相應的型別
1 // 這是迭代器的基類 所有迭代器必須定義這5種型別 2 template<class Category, class T, class Distance = ptrdiff_t, 3 class Pointer = T*, class Reference = T&> 4 struct iterator { 5 typedef Category iterator_category; 6 typedef T value_type; 7 typedef Distance difference_type; 8 typedef Pointer pointer; 9 typedef Reference reference;10 };View Code
2.定義萃取器iter_traits
1 // 以迭代器為模板參數,用於萃取相應的型別2 template <class Iterator>3 struct iter_traits {4 typedef typename Iterator::iterator_category iterator_category;5 typedef typename Iterator::value_type value_type;6 typedef typename Iterator::difference_type difference_type;7 typedef typename Iterator::pointer pointer;8 typedef typename Iterator::reference reference;9 };View Code
3.定義相應的偏特化版本(這就是為什麼要使用iter_traits封裝多一層),因為內建型別的迭代器並不是class,不能定義相應的型別。
1 // 原生指標的偏特化版 2 template <class T> 3 struct iter_traits<T*> { 4 typedef typename random_access_iter_tag iterator_category; 5 typedef typename T value_type; 6 typedef typename ptrdiff_t difference_type; 7 typedef typename T* pointer; 8 typedef typename T& reference; 9 };10 11 // 原生const的偏特化版12 template <class T>13 struct iter_traits<const T*> {14 typedef typename random_access_iter_tag iterator_category;15 typedef typename T value_type;16 typedef typename ptrdiff_t difference_type;17 typedef typename const T* pointer;18 typedef typename const T& reference;19 };View Code
4.5種迭代器類型,只是一個標誌,用於根據萃取出來的iterator_category來選擇相應的演算法。
1 struct input_iter_tag {};2 struct output_iter_tag {};3 struct forward_iter_tag : public input_iter_tag {};4 struct bidirectional_iter_tag : public forward_iter_tag {};5 struct random_access_iter_tag : public bidirectional_iter_tag {};View Code
下面是distance()的實現,展示了怎麼使用traits萃取相應的型別。
1 // input迭代器只支援operator++ 2 template<class InputIterator> 3 inline typename iter_traits<InputIterator>::difference_type 4 __distance(InputIterator first, InputIterator last, input_iter_tag) 5 { 6 iter_traits<InputIterator>::difference_type n = 0; 7 while (first != last) 8 { 9 first++;10 n++;11 }12 return n;13 }14 15 // random access迭代器支援迭代器之間的加減法16 template<class RandomAccessIterator>17 inline typename iter_traits<RandomAccessIterator>::difference_type18 __distance(RandomAccessIterator first, RandomAccessIterator last, random_access_iter_tag)19 {20 return last - first;21 }22 23 // 根據迭代器的iterator_category來調用適合的版本24 template<class Iterator>25 inline typename iter_traits<Iterator>::difference_type26 distance(Iterator first, Iterator last)27 {28 return __distance(first, last, iter_traits<Iterator>::iterator_category());29 }View Code
STL的__type_traits也是使用traits技法,它可以萃取一個class是否有不重要的建構函式、是否為POD類型等等。
1 // __type_traits也是運用traits技術 2 struct __true_type {}; 3 struct __false_type {}; 4 5 template <class type> 6 struct __type_traits { 7 // 預設為false 可以實現自己的偏特化版本 8 // 內建類型的偏特化版本定義在stl_config.h中 都是__true_type 9 typedef __false_type has_trivial_default_constructor;10 typedef __false_type has_trivial_copy_constructor;11 typedef __false_type has_trivial_assignment_operator;12 typedef __false_type has_trivial_destructor;13 typedef __false_type is_POD_type;14 };View Code
自訂的類型可以定義相應的偏特化版本,例如定義is_POD_type為__true_type,STL會在元素析構的時候只進行記憶體回收,而不調用解構函式以用來提高效率。
STL源碼剖析(迭代器)