1 template<typename T>
2 class List //鏈表
3 {
4 void insert_front(T value);
5 void insert_end(T value);
6 void display(ostream &os=cout) const;
7 private:
8 ListItem<T>* _end;
9 ListItem<T>* _front;
10 long _size;
11 };
12
13 template<typename T>
14 class ListItem //結點
15 {
16 public:
17 T get_value()const;
18 ListItem* next()const;
19 private:
20 T _value;
21 ListItem* _next;
22 };
23
24 //要定義迭代器須要封裝指針
25 template<class Item> // Item的實際參數是ListItem
26 struct ListIter
27 {
28 Item *ptr; //指向結點的指針,迭代器就是在此基礎上封裝
29
30 ListIter(Item *p=0):ptr(p){}//構造函數
31
32 Item& operator*()const{return *ptr;}//解引用
33 Item* operator->()const{return ptr;}//->操做符
34 //...
35 };
36
37 /*
38 這裏存在問題,咱們將listiter封裝,並於list綁定,用於泛型算法
39 時,沒法獲取iter所指對象型別以及迭代器距離,所指之物的引用和指針等,
40 STL中藉助模板類型推導來實現這一點
41 */
42 //第一想法是在模板形參表當中加入另外一個參數,即所指之物的類型,而後將雙參數的函數放在private中,在public接口函數中調用private函數
43
44 template<typename Item, typename value>
45 class Item
46 {
47 private:
48 void func_pri(Item iter,value v);
49 public:
50 void func(Item iter){func_pri(iter,*iter);}
51 };
52 //問題又來了,若是在返回值中想要獲取類型怎麼辦?C++ 的參數推導不能夠在返回值中使用,由於從C繼承而來的函數的必要因素是參數和函數名,調用
53 //一個函數並不須要返回值,所以若支持返回值自動推導,編譯器可能沒法獲知其類型
54
55 這裏還有一種方法完成:
56 template<class value>
57 class Iter // 在迭代器的定義中內嵌一個關於value_type的聲明
58 {
59 typedef value value_type;
60 };
61
62 template<class I>
63 typename Iter::value_type func(I i) //這是某個Iter適用的函數(泛型算法,並非Iter類的成員函數),算法的形參爲迭代器類型,在其中能夠訪問value_type,符合咱們的預期
64 {
65 return *i;
66 }
67
68 //只有一個小問題,和指針不兼容,由於指針不可內嵌聲明,由於它不是類類型。
69 咱們想到了C++中template編程的一種技法,即部分特化,注意部分特化和特化是不一樣的,特化後實質已經不是模板,而部分特化是對模板的一個特殊狀況,還是模板
70 接下來正式介紹traits技法
71
72 -------------------------------------------------------------------------------------------------
73 //trait技法
74 template<class I>
75 struct iterator_traits
76 {
77 typedef typename I::value_type value_type;
78 typedef typename I::iterator_category iterator_category;
79 /*此型別比較特殊,是由於iterator有5種(寫入、只讀、讀寫、雙向、隨機),應用於泛型算法時,不一樣算法針對不一樣類型的迭代器有不一樣的效率,應該分開實現
80 好比,對於+操做而言,隨機迭代器效率是O(1),寫入是O(n),應該針對隨機迭代器另行實現
81 讓咱們想到了函數重載,但問題是上面的不一樣類型的迭代器都是模板參數,編譯器沒法獲取它的類型,所以沒法重載,所以加入這一個參數做爲標誌,此標誌必須是類類型,才能夠推導進行重載決議
82 具體的實現見P95*/
83 typedef typename I::difference_type difference_type;
84 typedef typename I::pointer pointer;
85 typedef typename I::reference reference;
86 };
87 部分特化版本--原生指針
88 template<class P>
89 struct iterator_traits<P*>
90 {
91 typedef typename P value_type;
92 typedef typename random_access_iterator_tag iterator_category;
93 typedef typename ptrdiff_t difference_type;
94 typedef typename P* pointer;
95 typedef typename P& reference;
96 };
97
98 部分特化版本--const指針
99 template<class P>
100 struct iterator_traits<const P*>
101 {
102 typedef typename P value_type;
103 typedef typename random_access_iterator_tag iterator_category;
104 typedef typename ptrdiff_t difference_type;
105 typedef typename const P* pointer;
106 typedef typename const P& reference;
107 };
108 ------------------------------------------------------------------------------------------------------------------
109
110 template<class I>
111 typename iterator_traits<I>::value_type func(I i) //這個和上面的無區別,就是間接取了一下,但好處在於有部分特化版本,對於不一樣類型的參數會返回正確的類型
112 {
113 return *i;
114 }
115
116
117 咱們本身實現iterator的時候,能夠繼承iterator class,見P100