- 迭代器:依序巡防某個聚合物(容器)所含的各個元素,但是不需要暴露這個聚合物的內部表述方式
- 核心思想:將容器和算法分開,彼此獨立設計
- 容器和算法的泛型化,均可以使用模板,使用迭代器連接容器和算法
- 例子
template <class InputIterator,class T>
InputIterator find(InputIterator first,InputIterator last,const T& value){while (first != last && *first != value){++first;}return first;
}
- 迭代器 是一種類似智能指針的對象,最為關鍵的操作是內容提領和成員訪問。
- 因此最關鍵的操作是對operator* 和 operator->進行重載工作
- 參考 智能指針auto_ptr? (參考思想)
void func(){auto_ptr<std::string>ps(new std::string("input_string"));std::cout << *ps << std::endl; //輸出input_stringstd::cout << ps->size() << std::endl; //輸出 5//離開之前不需要使用delete進行資源的釋放 auto_ptr自動釋放內存
}
- 使用new動態配置一個初始值為?input_string 的string對象,并將所得到的一個結果(原生指針) 作為auto_ptr<std::string>對象的初始數值?
- auto_ptr里面放的是原生指針所指對象的型別,而不是原生指針的型別
- auto_ptr 的簡單實現
template<class T>
class auto_ptr{
public:explicit auto_ptr(T* p = 0):pointee(p){}template<class U>auto_ptr(auto_ptr<U>& rhs):pointee(rhs.release()){}~auto_ptr(){delete pointee;}template <class U>auto_ptr<T>& operator=(auto_ptr<U>& rhs){if (this != rhs)reset(rhs.release());return *this;}T& operator*() const {return *pointee;}T& operator->() const {return pointee;}T* get() const {return pointee;}private:T* pointee;
};
- 迭代器會暴露太多的細節,因此將迭代器交給了每一個專屬的 容器,這也就是為啥每一個容器都有自己的專屬迭代器的緣故
- 如何判斷迭代器所指對象的型別?使用函數模板的參數推導機制

- ?func()為對外的接口,實際操作是由func_impl()實現的
- func_impl是一個函數模板 一旦被調用 編譯器會自動進行模板的參數推導,推導出型別T?
- 迭代器所指對象的型別,稱為該迭代器的value type,雖然上面的參數型別的推導機制可以適用于value type,但是并非是通用的方法,如果value type必須用于函數的返回值,就無法使用template的參數推導機制,畢竟 這個只適用于參數的推導 ,不可以推導 函數的返回值
- 解決上面問題的辦法? 聲明內嵌型別?

- func()返回的型別必須加上關鍵詞typename,因為T是一個template的參數,在編譯器對其具現化之前,編譯器不知道T是什么東西,也就是編譯器無法知道MyIter<T>::value_type是什么類型,其代表的是一個型別?還是一個成員函數?還是數據成員?
- 關鍵詞typename相當于告訴編譯器 這是一個型別,才可以順利通過編譯
- 但是并不是所有的迭代器都是class type,原生指針就不是,如果不是class type是不可以為其定義內嵌型別的。但是STL容器必須接受原始指針作為一種迭代器,上述的辦法還是不足以解決這個問題,那么如何實現對于上述一般化概念針對特殊情況(例如 針對原生指針)進行特殊化處理呢?
- 使用template partial specialization就可以實現 (偏特化)
- 偏特化的含義:如果class template擁有一個以上的template參數,可以針對其中某個(或者數個,但不是全部)的template參數進行特殊化處理,即可以在泛化版本中提供一個特殊化的版本,也就是將泛化版本中的某些template參數賦予明確的指定
template <typename U,typename V,typename T>
class C{};
- 偏特化很容易讓我們陷入一種誤區,比如偏特化一定是對template參數U或者V或者T或者某種組合指定某個參數值,這是不對的
- 偏特化是提供另外一份template 定義式,但是本身仍然是templatized;針對任何template參數更進一步的條件限制所設計出來的一種特殊化版本
- 例:這個泛型版本允許接受T為任何型別
template <typename T>
class C{};
- 很容易接受他有如下形式的 偏特化設計
- 這個特殊化版本 僅僅適用于“T為原始指針”的情形,T為原生指針是相較于 T為任何型別的更進一步的限制
template <typename T>
class C<T*>{ };
- 解決內嵌型別未解決的問題,也就是 原生指針不是class,因此無法為其定義內嵌型別,因此可以針對 “迭代器之template參數為指針”設計特化版的迭代器
- 這個class template專門用于 萃取 迭代器的特性,value_type正是迭代器特性之一
template <class I>
struct iteraor_traits{ //traits的含義是 "特性"typedef typename I::value_type value_type;
};
- 這個traits的含義是 如果 I 定義有自己的value type通過這個traits就可以萃取得到的value_type就是I:: value_type,如果I定義有自己的value type 先前的func()可以進一步的改下成如下形式
template <class I>
typename iteraor_traits<I>::value_type //這一整行是函數的返回型別func(I ite){return *ite;}
- 這新增的一層間接性,可以帶來的好處是什么呢?可以為traits 進行偏特化的設計
- 令iterator_traits 擁有的一個偏特化的設計如下
template <class T>
struct iteraor_traits<T*>{ //偏特化版本 迭代器是一個原生指針typedef T value_type;};
- 于是 原生指針int* 雖然不是一種class type 但是仍然可以通過traits取到value type
- 注意:針對“指向常數對象的指針(pointer to const)” iterator_traits<const int *>::value_type
- 上述得到的結果是const int,而不是int,原本是希望聲明一個暫時的變量,使得其類型和迭代器的類型value_type一致,但是現在被const修飾無法賦值,不滿足需求,因此當迭代器是一個 pointer to const的類型,只能另外設計一個偏特化版本,讓value type指向的是non const版本即可
template <class T>
struct iterator_traits<const T*>{//偏特化版本 當迭代器的類型是pointer-to-const的時候//萃取出來的型別是 T 而不是const Ttypedef T value_type;
};
- 這樣的話 不管面對的是迭代器、原生指針int* 或者const int* 都可以通過traits 取出正確的 value type
- 使用traits 萃取各個迭代器的特性,這里特性是指 迭代器的相應的型別,但是需要每一個迭代器都需要使用內嵌型別定義的方式定義出相應的型別
