模板是c++中的泛型编程
test1.cpp
template<typename T>
T sum(T a ,T b)//定义点,编译模板的头部,调用点,编译模板体
{
return a+b;
}
template<typename T>
T sum(T a ,T b)//定义点,编译模板的头部,调用点,编译模板体
{
return a+b;
}
//template<typename T,typename L=double>//仅允许在类模板上使用默认模板参数,c++11添加了函数模板的默认值
template<typename T,typename L>
T getval()
{
T a=20;//初始化
return a ;
}
template<typename T,typename L>
T getval()
{
T a=20;//初始化
return a ;
}
template<typename T>
bool Compare(const T a ,const T b)
{
cout<<"compare(T)"<<typeid (T).name()<<endl;
return a>b;
}
bool Compare(const T a ,const T b)
{
cout<<"compare(T)"<<typeid (T).name()<<endl;
return a>b;
}
template<>//模板特例化,模板重载,模板特例化会在此编译模板函数,类型匹配直接调用即可,不需要编译器在生成模板函数
bool Compare<char *>(char *const a ,char * const b)
{
cout<<"compare(char * ,char *)"<<endl;
return strcmp(a,b)>0;
}
//template<>
//bool Compare<char *>(char *a ,char * b)
//{
// cout<<"compare(char * ,char *)"<<endl;
// return strcmp(a,b)>0;
//}
bool Compare<char *>(char *const a ,char * const b)
{
cout<<"compare(char * ,char *)"<<endl;
return strcmp(a,b)>0;
}
//template<>
//bool Compare<char *>(char *a ,char * b)
//{
// cout<<"compare(char * ,char *)"<<endl;
// return strcmp(a,b)>0;
//}
template<typename T,int size>//模板的参数列表可以有类型参数和非类型参数,非类型参数必须是常量,并且不允许double,float
void Show(T *arr)
{
//size=8;//error size不能改变
for(int i=0;i<size;++i)
{
cout<<arr[i]<<" ";
}
cout<<endl;
}
template <typename t>
t add(t a,t b);//模板声明
t add(t a,t b);//模板声明
int main()
{
sum<int>(10,20);//通过传入类型进行类型替换模板实例化生成模板函数,编译模板体,在调用点
//(typedef类型替换,在编译期间,有安全检查)
sum(10,20);//实参推演,根据传入的数值,编译器推测出实参类型,再进行模板实例化,类型必须精确匹配,不能产生二义性
//sum(10,20.1);//error,实参是int double,形参是T ,T不知道要匹配哪个实参,产生二义性
{
sum<int>(10,20);//通过传入类型进行类型替换模板实例化生成模板函数,编译模板体,在调用点
//(typedef类型替换,在编译期间,有安全检查)
sum(10,20);//实参推演,根据传入的数值,编译器推测出实参类型,再进行模板实例化,类型必须精确匹配,不能产生二义性
//sum(10,20.1);//error,实参是int double,形参是T ,T不知道要匹配哪个实参,产生二义性
//getval<int>();//error 没有与参数列表匹配的 函数模板 getval 的实例
getval<int,double>();//无参数,必须传入类型<int,double><typename T,typename L>一一对应
getval<int,double>();//无参数,必须传入类型<int,double><typename T,typename L>一一对应
Compare(10,20);
char *p="hello";
char *q="world";
Compare (p,q);//调用的是模板的特例化,函数重载调用顺序是普通函数>模板特例化>模板
Compare ("abdc","seda");//调用的是模板,因为形参是char const *
auto rt=getval<int ,double>();//auto自动识别变量的类型
cout<<typeid (rt).name()<<endl;
cout<<typeid (rt).name()<<endl;
int arr[]={23,4124,55,16,0,8};
Show<int,sizeof(arr)/sizeof(arr[0])>(arr);
Show<int,sizeof(arr)/sizeof(arr[0])>(arr);
add(10,20);///
return 0;
}
}
test2.cpp
template <typename t>
t add(t a,t b)
{
return a+b;
}
//编译错误,找不到外部引用的符号,因为模板在编译的时候只编译头部,只有在调用点才编译模板体,文件分开编译,所以
//找不到文件的模板体
t add(t a,t b)
{
return a+b;
}
//编译错误,找不到外部引用的符号,因为模板在编译的时候只编译头部,只有在调用点才编译模板体,文件分开编译,所以
//找不到文件的模板体
template int add<int>(int ,int);//显示实例化,不管有无调用,都要生成一个模板函数
//但是不可能每调用一次就显示实例化一次,所以定义在头文件中是最好的,引用头文件时,会在预编译阶段展开代码,编译
//可以找到模板体,内联函数一般也写在头文件中
//但是不可能每调用一次就显示实例化一次,所以定义在头文件中是最好的,引用头文件时,会在预编译阶段展开代码,编译
//可以找到模板体,内联函数一般也写在头文件中