模板
模板就是实现代码重用机制的一种工具,它可以实现类型参数化,即把类型定义为参数, 从而实现了真正的代码可重用性。模版可以分为两类,一个是类模版,另一个是函数模版。
类模板
template<typename T1,typename T2 int len= 7>
class test{
private:
T1 m_First;
T2 m_Second;
int m_cnt;
public:
test(T1 first,T2 second,int c=len):m_First(first),m_Second(second),m_cnt(c)
};
说明:typename是类型名关键字,个数不限。模板里面也可以有非类型的参数,原则上只能是整数,而且是字面量(编译时就确定下来);也可以有默认值。
最好不要把模板的声明与定义分开,因为若是成员函数中有类型参数存在,则需要在成员函数定义之前进行模板声明,并且在成员函数名前加上“ 类名<类型参数>::“
想查看实际替换时是什么类型,这就需要运行时类型识别函数了typeid
#include<iostream>
#include<string>
#include<typeinfo>
using namespace std;
template<typename T>
class test
{
public:
static string name();
};
//类外函数定义
template<typename T> //必须添加表明下面是模板
string test<T>::name() //类外定义静态成员函数不能加static,与静态变量赋值类似
{
return typeid(T).name();
}
//类模板特化
template<> //必须
class test<char>
{
public:
static string name(){return "const char*";}
};
template<typename T>
class test<T*>
{
public:
static string name(){ return test<T>::name()+"_pointer";}
};
int main()
{
cout <<"string:" << test<string>::name() <<endl; //静态类的调用方法
cout << "char:" << test<char>::name() << endl;
cout << "char*" << test<char*>::name() << endl;
return 0;
}
模板偏特化
模板偏特化是通过"给模板中的部分模板参数以具体的类,而留下剩余的模板参数仍然使用原来的泛化定义"的方式来实现的
#include<iostream>
using namespace std;
template <int n> //无类型参数
class fact
{
public:
enum {val = fact<n-1>::val*n};
};
template<>
class fact<0> //特化
{
public:
enum{val = 1};
};
int main()
{
cout << fact<6>::val << endl; //模板实例化
return 0;
}
全特化
//模板全特化 对比1 2中模板格式
template<>
class test<int*,char,1024>
{
private:
string m_First;
T2 m_Second;
int m_cnt;
public:
test(int* first,char second,int c=1024):m_First(first),m_Second(second),m_cnt(c)
};
模板,偏特化,全特化,最佳匹配
.当你实例化一个模板时,编译器会把目前存在的偏特化模板和全特化模板做比较,并找出其中最合适、最匹配的实现.
//测试匹配偏特化,全特化
#include<iostream>
using namespace std;
template<typename T1,typename T2>
class test
{
public:
void name(){cout << "类模板" << endl;}
};
//偏特化1
template<typename T1>
class test<T1,int>
{
public:
void name(){cout << "偏特化,T2 = int"<< endl;}
};
//偏特化2 与偏特化1产生二义性
// template<typename T1>
// class test<T1,T1>
// {
// public:
// void name(){cout << "偏特化,同类型匹配" <<endl;}
// };
//全特化
// template<>
// class test<int,int>
// {
// public:
// void name(){cout << "全特化:int int" << endl;}
// };
int main()
{
test<int,int>().name();
return 0;
}
函数模板
template<typename T>
T Max(T a,T b)
{
return a>b?a:b;
}
匹配:函数模板可以根据实参的传值类型自动生成对应类型函数,但是返回值必须指定,因为返回值是不可推断的
偏特化:函数模板只支持全特化,不支持偏特化
函数模板重载: 函数模板与同名的非模板函数可以重载,这种情况下,调用时先找参数完全匹配的非模板函数,如果找不到就调用匹配的模板函数。
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
//普通函数模板
template<typename T>
void sort(T a[], int n)
{
for(int i=0; i<n-1; i++)
{
int min = i;
for(int j=i+1; j<n; j++)
if(a[j]<a[min])
min = j;
swap(a[min],a[i]);
}
}
//特化模板1字符串指针
template<>
void sort(const char* a[], int n)
{
for(int i=0; i<n-1; i++)
{
int min = i;
for(int j=i+1; j<n; j++)
if(strcmp(a[j],a[min])==-1)//字符串比较-1 0 1
min = j;
swap(a[min],a[i]);
}
}
//特化模板2指针
template<typename T>
void sort(T* a[], int n)
{
for(int i=0; i<n-1; i++)
{
int min = i;
for(int j=i+1; j<n; j++)
if(*a[j]<*a[min])
min = j;
swap(a[min],a[i]);
}
}
//重载<操作符,完成结构体排序
class date
{
int year;
int month;
int day;
public:
date(int y,int m,int d):year(y),month(m),day(d){}
bool operator<(const date& d)const
{
if(this->year < d.year) return 1;
else if(this->year == d.year)
{
if(this->month < d.month) return 1;
else if(this->month == d.month)
{
if(this->day < d.day) return 1;
}
}
return 0;
}
friend ostream& operator<<(ostream& os,const date& d)
{
return os<< d.year <<"-"<<d.month << "-" << d.day;
}
};
//输出数组元素的内容
template<typename T>
void show(T a[],int n) // n = sizeof(a)/sizeof(a[0]);
{
for(int i = 0 ;i < n; i++)
{
cout << a[i] << " ";
}
cout << endl;
}
template<typename T>
void show(T *a[],int n)
{
for(int i = 0 ;i < n; i++)
{
cout << *a[i] << " ";
}
cout << endl;
}
int main()
{
//普通模板测试
double d[5] = {12.5,45.6,3.2,99.9,56.89};
sort(d,5);
show(d,5);
//字符串指针模板测试
const char* str[3] = {"hello","world","thanks"};
sort(str,3);
show(str,3);
//指针数组测试
int *ptri[5] = {new int(5),new int(45),new int(58),new int(99),new int(158)};
sort(ptri,5);
show(ptri,5);
//date结构体测试
date dd[3] = {{1998,10,12},{2012,12,12},{2014,3,21}};
sort(dd,3);
show(dd,3);
return 0;
}
输出结果: