很久没有写博客了,学习进入了迷茫期或者是困顿期,不知道下一步该怎么走了。一边想学习算法,扎实功底,一边又想学系统编程(网络编程和多线程编程)。
闲言少叙,书归正传。
最近看侯杰讲解STL,其中泛型我不是太明白,因此专门查了查资料,学习了一下。资料如下:http://www.cnblogs.com/gw811/archive/2012/10/25/2738929.html
我自己学习的总结如下:
模板分为两种:函数模板和类模板。
函数模板的格式如下:
template<class name1,class name2***,class namen> returnType functionName(name1,name2****namen){}
调用模板函数时,需要直接传递进入实参,编译器会推算出所使用的类型。这就是传说中的实参推演。
类模板的声明格式如下:
template<class name1,class name2***,class namen> class classname{}
定义格式如下:
template<class name1,class name2***,class namen> returnType classname<name1,name2***,namen>::functionName(?????){}
类模板不存在实参推演的问题。因此每次使用需要指定类型。
模板形参分三种类型:类型形参,非类型形参,以及默认模板形参。
类型形参:就是我们最常使用的通过class或者typename定义的形参。例子如下:
1 #pragma once 2 #ifndef __TEMPLATE_DEMO__ 3 #define __TEMPLATE_DEMO__ 4 5 template <class T> class A 6 { 7 public: 8 T g(T a, T b); 9 A(); 10 }; 11 12 template <class T> A<T>::A() 13 {} 14 15 template <class T> T A<T>::g(T a, T b) 16 { 17 return a + b; 18 } 19 20 template <class T1> void fun(T1 a, T1 b) 21 { 22 cout << a << endl; 23 cout << b << endl; 24 } 25 #endif // !__TEMPLATE_DEMO__
cpp调用代码如下:
1 // ConsoleApplication37.cpp : 定义控制台应用程序的入口点。 2 // 3 4 #include "stdafx.h" 5 #include <iostream> 6 #include "TemplateDemo.h" 7 8 using namespace std; 9 10 11 int main() 12 { 13 A<int> a; 14 int c = 1, d = 2; 15 cout << a.g(2,3.2) << endl; 16 fun(c,d); 17 system("pause"); 18 return 0; 19 }
这里需要注意的是,所有的模板实现代码都需要在头文件中定义实现。
非类型形参:就是内置类型形参。
非类型形参在模板内部为常量,只能是整型,指针,引用中的一种,且在编译期间就必须是常量。例子如下:
1 #pragma once 2 #ifndef __TEMPLATE_DEMO__ 3 #define __TEMPLATE_DEMO__ 4 5 template<class T, int MAXSIZE> class Stack 6 { 7 8 private: 9 T elements[MAXSIZE]; 10 int count; 11 public: 12 Stack(); 13 void push(T const&); 14 T pop(); 15 T top() const; 16 bool empty() const 17 { 18 return count == 0; 19 } 20 bool full() const 21 { 22 return count == MAXSIZE; 23 } 24 }; 25 26 27 template<class T, int MAXSIZE> Stack<T, MAXSIZE>::Stack() :count(0) 28 { 29 30 } 31 32 template<class T, int MAXSIZE> void Stack<T, MAXSIZE>::push(T const& elem) 33 { 34 if (count == MAXSIZE) 35 { 36 throw std::out_of_range("out of range stack is full"); 37 } 38 elements[count] = elem; 39 ++count; 40 } 41 42 template<class T, int MAXSIZE> T Stack<T, MAXSIZE>::pop() 43 { 44 if (count == 0) 45 { 46 throw std::out_of_range("out of range stack is empty"); 47 } 48 T t = elements[count-1]; 49 --count; 50 return t; 51 } 52 53 template<class T, int MAXSIZE> T Stack<T, MAXSIZE>::top() const 54 { 55 if (count == 0) 56 { 57 throw std::out_of_range("out of range stack is empty"); 58 } 59 return elements[count - 1]; 60 } 61 62 63 64 #endif // !__TEMPLATE_DEMO__
cpp调用代码如下:
1 // ConsoleApplication38.cpp : 定义控制台应用程序的入口点。 2 // 3 4 #include "stdafx.h" 5 #include "TemplateDemo.h" 6 #include <string> 7 #include <iostream> 8 9 using namespace std; 10 11 int main() 12 { 13 try 14 { 15 Stack<int, 20> int20stack; 16 Stack<int, 40> int40stack; 17 Stack<string, 40> stringstack; 18 int20stack.push(7); 19 cout << int20stack.pop() << endl; 20 system("pause"); 21 22 stringstack.push("hello"); 23 cout << stringstack.top() << endl; 24 stringstack.pop(); 25 stringstack.pop(); 26 system("pause"); 27 return 0; 28 } 29 catch (exception const& ex) { 30 cerr << "Exception: " << ex.what() << endl; 31 system("pause"); 32 return EXIT_FAILURE; 33 } 34 }
默认模板形参:
可以为类模板的类型形参提供默认值,不能为函数模板的类型形参提供默认值,类和函数模板都可以为非类型形参提供默认值。
类模板如果有多个类型形参,且从某一个开始设置了默认值,则从这一个开始之后的形参,都需要设置默认值。
在定义类模板时,默认形参的值需要省略(vs2015验证不通过)。
实例如下:
1 #pragma once 2 #ifndef __TEMPLATE_DEMO__ 3 #define __TEMPLATE_DEMO__ 4 5 template<class T1=int, class T2> class Demo 6 { 7 public: 8 int execute(T1 a, T2 b); 9 }; 10 11 12 template<class T1, class T2> int Demo<T1, T2>::execute(T1 a, T2 b) 13 { 14 return a + b; 15 } 16 17 #endif // !__TEMPLATE_DEMO__
cpp调用代码如下:
1 // ConsoleApplication41.cpp : 定义控制台应用程序的入口点。 2 // 3 4 #include "stdafx.h" 5 #include "TemplateDemo.h" 6 #include <iostream> 7 8 using namespace std; 9 10 int main() 11 { 12 Demo<int,int> demo; 13 cout << demo.execute(1,3) << endl; 14 system("pause"); 15 return 0; 16 }
编译后结果报错:缺少默认模板参数:参数2。
将头文件修改成如下形式:
1 #pragma once 2 #ifndef __TEMPLATE_DEMO__ 3 #define __TEMPLATE_DEMO__ 4 5 template<class T1=int, class T2=int> class Demo 6 { 7 public: 8 int execute(T1 a, T2 b); 9 }; 10 11 12 template<class T1, class T2> int Demo<T1, T2>::execute(T1 a, T2 b) 13 { 14 return a + b; 15 } 16 17 #endif // !__TEMPLATE_DEMO__
然后编译通过,运行结果为4.
模板偏特化:
就是说,我们通过模板编程来包含所有的类型,因此只需要一个模板方法就可以替代所有的类型了,但是,在一些特殊类型时,我们有更高效的实现方式,希望在使用这种类型时,我们使用这种更高效的实现,因此就有了模板偏特化的说法。
1 #pragma once 2 #ifndef __TEMPLATE_DEMO__ 3 #define __TEMPLATE_DEMO__ 4 #include <iostream> 5 6 template<typename T1, typename T2> class Demo 7 { 8 public: 9 int execute(T1,T2); 10 }; 11 12 template<> class Demo<double,double> 13 { 14 public: 15 int execute(double a, double b) 16 { 17 std::cout << "in double type:" << std::endl; 18 std::cout << "a;" << a << std::endl; 19 std::cout << "b;" << b << std::endl; 20 return a / b; 21 } 22 }; 23 24 template<typename T1> class Demo<T1, int> 25 { 26 public: 27 int execute(T1,int); 28 }; 29 30 31 template<typename T1, typename T2> int Demo<T1, T2>::execute(T1 a, T2 b) 32 { 33 std::cout << "in generic:" << std::endl; 34 std::cout << "a;" << a << std::endl; 35 std::cout << "b;" << b << std::endl; 36 return a + b; 37 } 38 39 template<typename T1> int Demo<T1, int>::execute(T1 a, int b) 40 { 41 std::cout << "in int type:" << std::endl; 42 std::cout << "a;" << a << std::endl; 43 std::cout << "b;" << b << std::endl; 44 return a * b; 45 } 46 47 #endif // !__TEMPLATE_DEMO__
cpp代码如下:
1 // ConsoleApplication42.cpp : 定义控制台应用程序的入口点。 2 // 3 4 #include "stdafx.h" 5 #include <iostream> 6 #include "TemplateDemo.h" 7 8 using namespace std; 9 10 int main() 11 { 12 Demo<short, short> demo1; 13 demo1.execute(1,2); 14 15 Demo<int, int> demo2; 16 demo2.execute(1,2); 17 18 Demo<double, double> demo3; 19 demo3.execute(1.2,1.2); 20 21 system("pause"); 22 return 0; 23 }
运行结果如下,不同的类型进入到不同的模板实例。
这里记录一个问题:在全特化中的实现中,如果单独定义,则会编译不通过。