码迷,mamicode.com
首页 > 编程语言 > 详细

Standard C++ Episode 10

时间:2015-08-21 07:06:33      阅读:259      评论:0      收藏:0      [点我收藏+]

标签:

一、为什么要有模板?
将类型参数化,可以实现算法与类型的分离,编写针对类型更加抽象的函数或者类。
二、函数模板
通用定义:
template<typename 类型形参1, ...>
返回类型 函数模板名 (形参表) { ... }
特化定义:
template<>

返回类型 函数模板名<类型实参1, ...> (形参表) { ... }

 1 /* 函数模板(模板函数)练习
 2  * */
 3 #include <iostream>
 4 #include <typeinfo>
 5 #include <cstring>
 6 using namespace std;
 7 
 8 
 9 template<typename T/*类型形式参数表*/>
10 //typename关键字声明了类型形式参数表,早期这里采用的关键字是class,早期就直接用关键字class来声明类型形式参数, 在这里class就是typename, typename就是class, 没有区别!
11 T Max (T x, T y) 
12 {//编译期编译此处时,不进行实际编译,只进行基本的类型检查,当后期有模板的实例要进行编译时,根据实例化时候给出的实际类型参数进行编译,这称为"后期编译"。
13 //后期编译,在获得实际类型参数时进行编译,也就是说一个模板函数或许在编译期被编译为多个具体的函数。
14     cout << typeid (T).name () << endl;
15     return x > y ? x : y;
16 }
17 
18 // 模板特化
19 template<>//缺少后部分编译器会报错,部分容错性比较好的编译器能够自动识别同名于模板函数的函数为其特化。
20 char* Max<char* /*可以省略,编译器可以根据后边括号中的char*隐式推断出来这里的char**/> (char* x, char* y) 
21 {//当编译期获得实际类型参数是char*时,按照该特化的模板编译。
22     return strcmp (x, y) > 0 ? x : y;
23 }
24 template<typename T>
25 void foo (void) {
26     T t;
27     cout << typeid (t).name () << endl;
28 }
29 int main (void) {
30     cout << "输入两个整数:" << flush;
31     int nx, ny;
32     cin >> nx >> ny;
33     cout << "最大值:" << Max<int/*类型实际参数*/> (nx, ny) << endl;//获得Max的实际类型参数表后进行编译,这叫做"后期编译"。
34     cout << "输入两个字符串:" << flush;
35     string sx, sy;
36     cin >> sx >> sy;
37     cout << "最大值:" << Max (sx, sy) << endl;//编译器自动推断类型实际参数,最终编译函数string Max(string, string);
38     cout << "输入两个字符串:" << flush;
39     foo<int> ();//编译器不能自动推断类型实际参数,必须显式的给出类型实际参数表。
40     foo<double> ();
41     foo<string> ();
42 
43     char cx[256], cy[256];
44     cin >> cx >> cy;
45     cout << "最大值:" << Max<char*> (cx, cy) << endl;//编译函数char* Max(chat*, char*);
46 
47 
48     return 0;
49 }

 

 

三、类模板
通用定义:
template<typename 类型形参1, ...>
class 类模板名 { ... };
全类特化:
template<>
class 类模板名<类型实参1, ...> { ... };
成员特化:
template<>

返回类型 类模板名<类型实参1, ...>::成员函数名 (形参表) { ... }

 1 /*类模板练习
 2  * */
 3 #include <iostream>
 4 #include <cstring>
 5 using namespace std;
 6 // 通用模板
 7 template<typename T>
 8 class Comparator {
 9 public:
10     Comparator (T x, T y) : m_x (x), m_y (y) {}
11     T min (void) const {
12         return m_x < m_y ? m_x : m_y;
13     }
14     T max (void) const {
15         return m_x > m_y ? m_x : m_y;
16     }
17 private:
18     T m_x;
19     T m_y;
20 };
21 /*
22 // 针对char*的全模板特化
23 template<>
24 class Comparator<char*> {
25 public:
26     Comparator (char* x, char* y) :
27         m_x (x), m_y (y) {}
28     char* min (void) const {
29         return strcmp (m_x, m_y) < 0 ? m_x : m_y;
30     }
31     char* max (void) const {
32         return strcmp (m_x, m_y) > 0 ? m_x : m_y;
33     }
34 private:
35     char* m_x;
36     char* m_y;
37 };
38 */
39 // 针对char*的成员函数特化
40 template<>
41 char* Comparator<char*>::min (void) const {
42     return strcmp (m_x, m_y) < 0 ? m_x : m_y;
43 }
44 template<>
45 char* Comparator<char*>::max (void) const {
46     return strcmp (m_x, m_y) > 0 ? m_x : m_y;
47 }
48 int main (void) {
49     cout << "输入两个整数:" << flush;
50     int nx, ny;
51     cin >> nx >> ny;
52     Comparator<int> cn (nx, ny);// 编译期使用实际类型参数表进行模板实例化,运行期使用实例化后的类进行对象实例化。
53     cout << "最小值:" << cn.min () << endl;
54     cout << "最大值:" << cn.max () << endl;
55     cout << "输入两个字符串:" << flush;
56     string sx, sy;
57     cin >> sx >> sy;
58     Comparator<string> cs (sx, sy);
59     cout << "最小值:" << cs.min () << endl;
60     cout << "最大值:" << cs.max () << endl;
61     cout << "输入两个字符串:" << flush;
62     char cx[256], cy[256];
63     cin >> cx >> cy;
64     Comparator<char*> cc (cx, cy);
65     cout << "最小值:" << cc.min () << endl;
66     cout << "最大值:" << cc.max () << endl;
67     return 0;
68 }

 

 

 

四、局部特化

 1 /*
 2  * 模板的局部特化
 3  * */
 4 #include <iostream>
 5 using namespace std;
 6 template<typename T1, typename T2>
 7 class A {
 8 public:
 9     A (void) {
10         cout << "A<T1,T2>" << endl;
11     }
12 };
13 template<typename T1>
14 class A<T1, int> {
15 public:
16     A (void) {
17         cout << "A<T1,int>" << endl;
18     }
19 };
20 template<>
21 class A<int, int> {
22 public:
23     A (void) {
24         cout << "A<int,int>" << endl;
25     }
26 };
27 template<typename T>
28 class B {
29 public:
30     B (void) {
31         cout << "B<T>" << endl;
32     }
33 };
34 template<typename T>
35 class B<T*> {
36 public:
37     B (void) {
38         cout << "B<T*>" << endl;
39     }
40 };
41 template<typename T>
42 class B<T[]> {
43 public:
44     B (void) {
45         cout << "B<T[]>" << endl;
46     }
47 };
48 template<typename T1, typename T2, typename T3>
49 class C {
50 public:
51     C (void) {
52         cout << "C<T1,T2,T3>" << endl;
53     }
54 };
55 template<typename T1, typename T2>
56 class C<T1, T2, T2> {
57 public:
58     C (void) {
59         cout << "C<T1,T2,T2>" << endl;
60     }
61 };
62 template<typename T1>
63 class C<T1, T1*, T1*> {
64 public:
65     C (void) {
66         cout << "C<T1,T1*,T1*>" << endl;
67     }
68 };
69 int main (void) {
70     // 特化程度高(具体化程度高,模板实例化程度高)的优先
71     A<double, double> a1;
72     A<double, int> a2;
73     A<int, int> a3;
74     // 针对指针和数组的特化优先
75     B<char> b1;
76     B<char*> b2;
77     B<char[]> b3;
78     // 匹配度高的特化优先
79     C<char, short, long> c1;
80     C<char, short, short> c2;
81     C<char, char*, char*> c3;
82     return 0;
83 }

 

 

五、非类型参数和缺省参数
1.非类型参数的实参仅限于常量或者常量表达式。

2.无论类型参数还是非类型参数都可以带有缺省值,而且和函数的缺省参数一样,模板的缺省参数也必须靠右。

 

 1 #include <iostream>
 2 using namespace std;
 3 template<typename T = int, size_t S = 5>
 4 class Array {
 5 public:
 6     T& operator[] (size_t i) {
 7         return m_array[i];
 8     }
 9     const T& operator[] (size_t i) const {
10         return const_cast<Array&> (*this) [i];
11     }
12     size_t size (void) const {
13         return S;
14     }
15     friend ostream& operator<< (ostream& os,
16         const Array& arr) {
17         for (size_t i = 0; i < arr.size (); ++i)
18             os << ( << arr.m_array[i] << );
19         return os;
20     }
21 private:
22     T m_array[S];
23 };
24 int main (void) {
25     const /*volatile*/ int x = 3, y = 7;//对于具有常属性的变量,编译器在编译期进行优化,会把常属性的变量替换为常量,以图通过立即数来提高访问效率。通过关键字volatile可以取消编译器的这种优化。
26     Array<int, x+y> arr;//非类型实际参数只能是常量表达式
27     for (size_t i = 0; i < arr.size (); ++i)
28         arr[i] = i;
29     cout << arr << endl;
30     Array<Array<int, 4>, 3> m;
31     for (size_t i = 0; i < m.size (); ++i)
32         for (size_t j = 0; j < m[i].size (); ++j)
33             m[i][j] = i * m[i].size () + j;
34     cout << m << endl;
35     Array<double> a2;
36     Array<> a3;
37     return 0;
38 }

 

 

 1 #include <iostream>
 2 using namespace std;
 3 
 4 template<typename T>
 5 class A {
 6 public:
 7     class B {};
 8 };
 9 
10 template<typename T>
11 void foo (void) {
12     typename A<T>::B b;//直接写A<T>::B b;编译报错。因编译期初期不会将模板编译成代码,所以A<T>此时还是一个不明的模板类名称,取一个不明模板类作用域里面的B,在编译器进行模板的语法检查时候被编译器报错。可以通过关键字typename来告诉编译器A<T>是后期编译的一个类型名称。
13     //这里的typename不可以换为class.这里的typename关键字是告诉编译器A<T>::B是个类型名称
14 }
15 
16 
17 int main (void) {
18     foo<int> ();
19     return 0;
20 }

 

 

六、有关模板的其它问题

1.从模板继承

 1 /*
 2  * 类模板中的继承-从类模板继承
 3  * */
 4 #include <iostream>
 5 using namespace std;
 6 template<typename T>
 7 class A {
 8 public:
 9     A (const T& t) : m_t (t) {}
10     T m_t;
11 };
12 template<typename T, typename Y>
13 class B : public A<T>/*A是模板名称,A<T>是类名称*/ {
14 public:
15     B (const T& t, const Y& y) :
16         A<T> (t), m_y (y) {}
17     Y m_y;
18 };
19 int main (void) {
20     B<int, string> b (100, "hello");
21     cout << b.m_t <<   << b.m_y << endl;
22     return 0;
23 }

 

 

2.向模板派生

 1 /*
 2  * 向模板派生
 3  * 例如本例程:基类具体类,派生类是类模板
 4  * 
 5  * */
 6 #include <iostream>
 7 using namespace std;
 8 template<typename BASE>
 9 class Shape : public BASE {
10 public:
11     void draw (void) const {
12         BASE::draw ();
13     }
14 };
15 class Rect {
16 public:
17     void draw (void) const {
18         cout << "绘制矩形..." << endl;
19     }
20 };
21 class Circle {
22 public:
23     void draw (void) const {
24         cout << "绘制圆形..." << endl;
25     }
26 };
27 int main (void) {
28     Shape<Rect> shape1;
29     shape1.draw ();
30     Shape<Circle> shape2;
31     shape2.draw ();
32     return 0;
33 }

 

 

3.模板中模板成员

1)模板型成员变量

2)模板型成员函数

3)模板型成员类型(内部类)

4.模板型模板实参

 1 /*
 2  *模板型成员变量
 3  */
 4 #include <iostream>
 5 using namespace std;
 6 
 7 template<typename T>
 8 class A {
 9 public:
10     A (const T& t) : m_t (t) {}
11     T m_t;
12 };
13 
14 template<typename T, typename Y>
15 class B {
16 public:
17     B (const T& t, const Y& y) :
18         m_a (t), m_y (y) {}
19     A<T> m_a;
20     Y m_y;
21 };
22 
23 
24 int main (void) {
25     B<int, string> b (100, "hello");
26     cout << b.m_a.m_t <<   << b.m_y << endl;
27     return 0;
28 }

 

 

 1 /*
 2  * 模板型成员函数
 3  * */
 4 #include <iostream>
 5 using namespace std;
 6 template<typename T>
 7 class A {
 8 public:
 9     A (const T& t) : m_t (t) {}
10     /*
11     template<typename Y>
12     void print (const Y& y) {
13         cout << m_t << ‘ ‘ << y << endl;
14     }
15     */
16     template<typename Y>
17     void print (const Y& y);
18     T m_t;
19 };
20 template<typename T>
21     template<typename Y>
22 void A<T>::print (const Y& y) {
23     cout << m_t <<   << y << endl;
24 }
25 int main (void) {
26     A<int> a (100);
27     a.print<string> ("hello");
28     return 0;
29 }

 

 

 1 /*
 2  * 模板型成员类型(内部类)
 3  *
 4  * */
 5 #include <iostream>
 6 using namespace std;
 7 template<typename T, typename Y>
 8 class A {
 9 public:
10     A (const T& t, const Y& y) :
11         m_t (t), m_b (y) {}
12     /*
13     template<typename X>
14     class B {
15     public:
16         B (const X& x) : m_x (x) {}
17         X m_x;
18     };
19     */
20     template<typename X> class B;//声明模板B
21     T m_t;
22     B<Y> m_b;
23 };
24 template<typename T, typename Y>
25     template<typename X>
26 class A<T, Y>::B {
27 public:
28     B (const X& x) : m_x (x) {}
29     X m_x;
30 };
31 int main (void) {
32     A<int, string> a (100, "hello");
33     cout << a.m_t <<   << a.m_b.m_x << endl;
34     return 0;
35 }

 

 

 1 /*
 2  * 模板型模板实参(模板作为模板的实参)
 3  *
 4  * */
 5 #include <iostream>
 6 using namespace std;
 7 template<typename T>
 8 class A {
 9 public:
10     A (const T& t) : m_t (t) {}
11     T m_t;
12 };
13 
14 template<typename X, typename Z,
15     template<typename T>  class Y/*Y是一个模板*/>//也可以写作template<class X, class Z, template<class T> class Y>
16 class B {
17 public:
18     B (const X& i, const Z& s) :
19         m_i (i), m_s (s) {}
20     Y<X> m_i;
21     Y<Z> m_s;
22 };
23 int main (void) {
24     B<int, string, A> b (100, "hello");
25     cout << b.m_i.m_t <<   << b.m_s.m_t << endl;
26     return 0;
27 }

 

 

七、容器和迭代器

  1 /*
  2  * 基于双向链表的容器的实现
  3  * 
  4  * */
  5 #include <iostream>
  6 #include <stdexcept>
  7 #include <cstring>
  8 using namespace std;
  9 // 双向线性链表容器模板
 10 template<typename T>
 11 class List {
 12 public:
 13     // 构造、析构、拷贝构造、拷贝赋值
 14     List (void) : m_head (NULL), m_tail (NULL) {}
 15     ~List (void) {
 16         clear ();
 17     }
 18     List (const List& that) : m_head (NULL),
 19         m_tail (NULL) {
 20         for (Node* node = that.m_head; node;
 21             node = node->m_next)
 22             push_back (node->m_data);
 23     }
 24     List& operator= (const List& that) {
 25         if (&that != this) {
 26             List list (that);
 27             swap (m_head, list.m_head);
 28             swap (m_tail, list.m_tail);
 29         }
 30         return *this;
 31     }
 32     // 获取首元素
 33     T& front (void) {
 34         if (empty ())
 35             throw underflow_error ("链表下溢!");
 36         return m_head->m_data;
 37     }
 38     const T& front (void) const {
 39         return const_cast<List*> (this)->front ();
 40     }
 41     // 向首部压入
 42     void push_front (const T& data) {
 43         m_head = new Node (data, NULL, m_head);
 44         if (m_head->m_next)
 45             m_head->m_next->m_prev = m_head;
 46         else
 47             m_tail = m_head;
 48     }
 49     // 从首部弹出
 50     void pop_front (void) {
 51         if (empty ())
 52             throw underflow_error ("链表下溢!");
 53         Node* next = m_head->m_next;
 54         delete m_head;
 55         m_head = next;
 56         if (m_head)
 57             m_head->m_prev = NULL;
 58         else
 59             m_tail = NULL;
 60     }
 61     // 获取尾元素
 62     T& back (void) {
 63         if (empty ())
 64             throw underflow_error ("链表下溢!");
 65         return m_tail->m_data;
 66     }
 67     const T& back (void) const {
 68         return const_cast<List*> (this)->back ();
 69     }
 70     // 向尾部压入
 71     void push_back (const T& data) {
 72         m_tail = new Node (data, m_tail);
 73         if (m_tail->m_prev)
 74             m_tail->m_prev->m_next = m_tail;
 75         else
 76             m_head = m_tail;
 77     }
 78     // 从尾部弹出
 79     void pop_back (void) {
 80         if (empty ())
 81             throw underflow_error ("链表下溢!");
 82         Node* prev = m_tail->m_prev;
 83         delete m_tail;
 84         m_tail = prev;
 85         if (m_tail)
 86             m_tail->m_next = NULL;
 87         else
 88             m_head = NULL;
 89     }
 90     // 删除所有匹配元素
 91     void remove (const T& data) {
 92         for (Node* node = m_head, *next; node;
 93             node = next) {
 94             next = node->m_next;
 95             if (equal (node->m_data, data)) {
 96                 if (node->m_prev)
 97                     node->m_prev->m_next =
 98                         node->m_next;
 99                 else
100                     m_head = node->m_next;
101                 if (node->m_next)
102                     node->m_next->m_prev =
103                         node->m_prev;
104                 else
105                     m_tail = node->m_prev;
106                 delete node;
107             }
108         }
109     }
110     // 清空
111     void clear (void) {
112         for (Node* next; m_head; m_head = next) {
113             next = m_head->m_next;
114             delete m_head;
115         }
116         m_tail = NULL;
117     }
118     // 判空
119     bool empty (void) const {
120         return ! m_head && ! m_tail;
121     }
122     // 获取大小
123     size_t size (void) const {
124         size_t count = 0;
125         for (Node* node = m_head; node;
126             node = node->m_next)
127             ++count;
128         return count;
129     }
130     // 插入输出流
131     friend ostream& operator<< (ostream& os,
132         const List& list) {
133         for (Node* node = list.m_head; node;
134             node = node->m_next)
135             os << *node;
136         return os;
137     }
138 private:
139     // 节点
140     class Node {
141     public:
142         Node (const T& data = 0, Node* prev = NULL,
143             Node* next = NULL) : m_data (data),
144             m_prev (prev), m_next (next) {}
145         friend ostream& operator<< (ostream& os,
146             const Node& node) {
147             return os << ( << node.m_data << );
148         }
149         T m_data; // 数据
150         Node* m_prev; // 前指针
151         Node* m_next; // 后指针
152     };
153     bool equal (const T& a, const T& b) const {
154         return a == b;
155     }
156     Node* m_head; // 头指针
157     Node* m_tail; // 尾指针
158 public:
159     // 正向迭代器
160     class Iterator {
161     public:
162         Iterator (Node* head = NULL,
163             Node* tail = NULL, Node* node = NULL) :
164             m_head (head), m_tail (tail),
165             m_node (node) {}
166         bool operator== (const Iterator& it) const {
167             return m_node == it.m_node;
168         }
169         bool operator!= (const Iterator& it) const {
170             return ! (*this == it);
171         }
172         Iterator& operator++ (void) {
173             if (m_node)
174                 m_node = m_node->m_next;
175             else
176                 m_node = m_head;
177             return *this;
178         }
179         const Iterator operator++ (int) {
180             Iterator old = *this;
181             ++*this;
182             return old;
183         }
184         Iterator& operator-- (void) {
185             if (m_node)
186                 m_node = m_node->m_prev;
187             else
188                 m_node = m_tail;
189             return *this;
190         }
191         const Iterator operator-- (int) {
192             Iterator old = *this;
193             --*this;
194             return old;
195         }
196         T& operator* (void) const {
197             return m_node->m_data;
198         }
199         T* operator-> (void) const {
200             return &**this;
201         }
202     private:
203         Node* m_head;
204         Node* m_tail;
205         Node* m_node;
206         friend class List;
207     };
208     Iterator begin (void) {
209         return Iterator (m_head, m_tail, m_head);
210     }
211     Iterator end (void) {
212         return Iterator (m_head, m_tail);
213     }
214     Iterator insert (Iterator loc, const T& data) {
215         if (loc == end ()) {
216             push_back (data);
217                return Iterator (m_head, m_tail,m_tail);
218         }
219         else {
220             Node* node = new Node (data,
221                 loc.m_node->m_prev, loc.m_node);
222             if (node->m_prev)
223                 node->m_prev->m_next = node;
224             else
225                 m_head = node;
226             node->m_next->m_prev = node;
227             return Iterator (m_head, m_tail, node);
228         }
229     }
230     Iterator erase (Iterator loc) {
231         if (loc == end ())
232             throw invalid_argument ("无效迭代器!");
233         if (loc.m_node->m_prev)
234             loc.m_node->m_prev->m_next =
235                 loc.m_node->m_next;
236         else
237             m_head = loc.m_node->m_next;
238         if (loc.m_node->m_next)
239             loc.m_node->m_next->m_prev =
240                 loc.m_node->m_prev;
241         else
242             m_tail = loc.m_node->m_prev;
243         Node* next = loc.m_node->m_next;
244         delete loc.m_node;
245         return Iterator (m_head, m_tail, next);
246     }
247 };
248 // 针对const char*的特化
249 template<>
250 bool List<const char*>::equal (const char* const& a,
251     const char* const& b) const {
252     return strcmp (a, b) == 0;
253 }
254 // 测试用例
255 int main (void) {
256     try {
257         List<int> list1;
258         list1.push_front (20);
259         list1.push_front (10);
260         list1.push_back (30);
261         list1.push_back (40);
262         cout << list1 << endl;
263         cout << list1.front () <<   <<
264             list1.back () << endl;
265         list1.pop_front ();
266         list1.pop_back ();
267         cout << list1 << endl;
268         ++list1.front ();
269         --list1.back ();
270         cout << list1 << endl;
271         list1.push_back (21);
272         list1.push_back (25);
273         list1.push_back (21);
274         list1.push_back (21);
275         cout << list1 << endl;
276         list1.remove (21);
277         cout << list1 << endl;
278         List<int> list2 = list1;
279         cout << list2 << endl;
280         list2.back () = 100;
281         cout << list2 << endl;
282         cout << list1 << endl;
283         list2 = list1;
284         cout << list2 << endl;
285         list2.front () = 100;
286         cout << list2 << endl;
287         cout << list1 << endl;
288         cout << list1.size () << endl;
289         list1.clear ();
290         cout << list1 << endl;
291         cout << boolalpha << list1.empty () << endl;
292 //        List<string> list3;
293         List<const char*> list3;
294         list3.push_back ("beijing");
295         list3.push_back ("tianjin");
296         list3.push_front ("tianjin");
297         list3.push_back ("shanghai");
298         list3.push_back ("beijing");
299         cout << list3 << endl;
300         list3.remove (string ("beijing").c_str ());
301         cout << list3 << endl;
302         for (List<const char*>::Iterator it =
303             list3.begin (); it != list3.end ();
304             ++it)
305             cout << *it <<  ;
306         cout << endl;
307         List<const char*>::Iterator it =
308             list3.begin ();
309         it++;
310         it = list3.insert (it, "chongqing");
311         cout << list3 << endl;
312         list3.erase (it);
313         cout << list3 << endl;
314     }
315     catch (exception& ex) {
316         cout << ex.what () << endl;
317         return -1;
318     }
319     return 0;
320 }

 

Standard C++ Episode 10

标签:

原文地址:http://www.cnblogs.com/libig/p/4746724.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!