标签:
一、为什么要有模板?
将类型参数化,可以实现算法与类型的分离,编写针对类型更加抽象的函数或者类。
二、函数模板
通用定义:
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 }
标签:
原文地址:http://www.cnblogs.com/libig/p/4746724.html