文章目录
1. 函数模板2. 类模板3. 模板特化3.1 函数模板特化3.2 类模板特化 4. 非类型模板参数模板是允许函数或类通过泛性的形式表现或运行的特性
1. 函数模板
模板可以使函数或者类只写一份代码而对应不同的类型
取整数、小数、字符中的最大值
#include <iostream>using namespace std;/*int Max(int a,int b){return a>b?a:b;}double Max(double a,double b){return a>b?a:b;}double Max(char a,char b){return a>b?a:b;}*/template<typename T> // 起一个模板类型名T Max(T a,T b){return a>b?a:b;}int main(){cout << Max(10,12) << endl; // int Max(int a,int b)cout << Max(1.0,1.2) << endl; // double Max(double a,double b)cout << Max('a','c') << endl; // char Max(char a,char b)}
结果为:
121.2c
两个对象交换顺序
#include <iostream>#include <sstream>using namespace std;/*void Swap(int& a,int& b){int t = a;a = b;b = t;}*/// 两个对象交换template <typename T>void Swap(T& a,T& b){T t = a;a = b;b = t;}int main(){{int a = 10;int b = 20;cout << a << "," << b << endl;Swap(a,b);// void Swap(int,int)cout << a << "," << b << endl;}{float a = 12.3;float b = 32.1;cout << a << "," << b << endl;Swap(a,b);// void Swap(double,double)cout << a << "," << b << endl;}}
结果为:
10,,1012.3,32.132.1,12.3
把某个类型转化为字符串
#include <iostream>#include <sstream>using namespace std;//把某个类型转换为字符串template <typename T>string NumberToString(T n){ostringstream oss;oss << n;return oss.str();}int main(){cout << NumberToString(10) << endl;cout << NumberToString(1.3) << endl;}
结果为:
101.3
对于不知道返回值类型的情况,我们需要用<尖括弧>设定类型
字符串转换为某个类型
#include <iostream>#include <sstream>using namespace std;// 字符串转换为某个类型template <typename T>T StringToNumber(const string& s){T res;istringstream iss(s);iss >> res;return res;}int main(){cout << StringToNumber<int>("20") << endl;cout << StringToNumber<float>("1.25") << endl;}
结果为:
201.25
对于传入两个数类型不一致,也可以做相应设定
#include <iostream>using namespace std;template<typename T>T Max(T a,T b){return a>b?a:b;}int main(){cout << Max((double)10,12.2) << endl;// 两个数类型不匹配 cout << Max<double>(10,12.2) << endl;}
结果为:
12.212.2
该程序不能使用小写max,会出现函数名冲突的情况
要想使用小写max,需要添加命名空间
#include <iostream>using namespace std;namespace My{// 添加命名空间template<typename T>T max(T a,T b){return a>b?a:b;}}int main(){cout << My::max((double)10,12.2) << endl;cout << My::max<double>(10,12.2) << endl;}
2. 类模板
与函数模板不同,类模板必须定义参数类型
求圆的周长和面积
#include <iostream>#include <cmath>using namespace std;// 圆形template <typename T>class Circle{T r;public:Circle(T r):r(r){}float GetLength() const{return 2*M_PI*r;}float GetArea() const{return M_PI*r*r;}};int main(){Circle<int> a(2); // 必须定义参数类型cout << a.GetLength() << "," << a.GetArea() << endl;Circle<double> b(2.2);cout << b.GetLength() << "," << b.GetArea() << endl;}
结果为:
12.5664,12.566413.823,15.2053
逐个创建数组并打印
#include <iostream>using namespace std;template <typename T> // 模板class SeqList{T* header;size_t count;public:SeqList():header(NULL),count(0){}// 构造函数// ~SeqList(){} 析构函数void Append(T val){// 添加元素T* temp = new T[count+1];// 申请一块儿新的连续的空间for(int i=0;i<count;++i){// 把原来的部分复制进来temp[i] = header[i];}temp[count] = val; // 把新加的数放到后面 ++count; // 数据个数加一delete [] header; // 把之前的空间释放掉header = temp; // 头指针指向新的顺序表}size_t GetSize() const{return count;} // 数据长度T Get(int i) {return header[i];}// 某个元素的值T& operator[](int i){return header[i];}// []运算符重载};int main(){{SeqList<int> arr; // 使用模板类,需要加类型arr.Append(2);arr.Append(4);arr.Append(3);arr.Append(5);for(int i=0;i<arr.GetSize();++i){// 逐个打印cout << arr.Get(i) << " ";}cout << endl;}{SeqList<float> arr; // 使用模板类,需要加类型arr.Append(2.2);arr.Append(4.4);arr.Append(3.3);arr.Append(5.5);for(int i=0;i<arr.GetSize();++i){// 逐个打印cout << arr[i] << " "; // 这里使用[]运算符重载}cout << endl;}}
结果为:
2 4 3 5 2.2 4.4 3.3 5.5
3. 模板特化
3.1 函数模板特化
出现问题:比较字符串大小时会出现比较错误的情况
#include <iostream>#include <sstream>using namespace std;template<typename T>T Max(T a,T b){return a>b?a:b;}int main(){cout << Max("abcd","defg") << endl;}
结果为:
abcd
比较错误的原因是:程序会按照地址进行比较,找出较大的那一个
解决方法:模板特化
#include <iostream>#include <sstream>#include <cstring>using namespace std;template<typename T>T Max(T a,T b){return a>b?a:b;}// 模板特化template<>const char* Max(const char* a,const char* b){return strcmp(a,b)>0?a:b;}int main(){cout << Max("abcd","defg") << endl;// cout << Max(string("abcd"),string("defg")) << endl;}
结果为:
defg
模板特化的作用:
特殊处理的模板,指定具体的模板类型
3.2 类模板特化
#include <iostream>#include <cmath>using namespace std;// 圆形template <typename T>class Circle{T r;public:Circle(T r):r(r){}float GetLength() const{return 2*M_PI*r;}float GetArea() const{return M_PI*r*r;}};// 模板特化template<>class Circle<int>{int r;public:Circle(int r):r(r){}float GetLength() const{cout << "Circle<int>:" ;return 2*M_PI*r;}float GetArea() const{cout << "Circle<int>:" ;return M_PI*r*r;}};int main(){Circle<int> a(2); // 这里使用的就是模板特化的类cout << a.GetLength() << "," << a.GetArea() << endl;Circle<double> b(2.2);cout << b.GetLength() << "," << b.GetArea() << endl;}
结果为:
Circle<int>:12.5664,Circle<int>:12.566413.823,15.2053
这个例子属于全特化
全特化:
声明一个模板空参数列表template<>在类名称后面的<>中显示指定类型
偏特化:
在一个模板类参数列表不指定或者指定部分具体类型在类名称后面的对应类型中显示指定该类型
template<typename T>class Test<T,int>{};
4. 非类型模板参数
#include <iostream>#include <cmath>using namespace std;template<typename T,int n> // 非类型模板参数void PrintArr(const T (&arr)[n]){// 只针对数组的特殊写法for(int i=0;i<n;++i){cout << arr[i] << " ";}cout << endl;}int main(){int arr[] = {1,3,5,7}; // int [4]PrintArr(arr);// 可以检测到数据数量char str[] = "abcd"; // char [5]PrintArr(str);float fs[] = {1.1,2.2,3.3};PrintArr(fs);// PrintArr(const float (&arr)[3])}
结果为:
1 3 5 7 a b c d 1.1 2.2 3.3
优化:函数模板参数尽量使用引用类型 const &
对象内容不改变对象是在函数外定义的
例如:
Circle(const T& r):r(r){}
const T& Max(const T& a,const T& b){
可以避免拷贝构造
template <typename T> 也可以写成 template <class T>