函数模板
通常int sum(int a, int b){return a+b;}这里的两个形参变量a b,就是为了接受实参的值。而模板的意义就在于此,模板就是针对类型的,使类型也可以进行参数化,即由原来的的固定的转化为可变的。
模板的意义:对类型也可以进行参数化了
- 函数模板:
“{}”里面的内容不进行编译,类型不知道
1、定义一个模板形参列表 :
template< typename T>;
2、定义一个通用的的模板;
bool compare(T a, T b)//compare是一个函数模板,compare+模板类型<>=函数
{
cout << "template compare" << endl;
return a > b;
}
- 模板类型参数:
可以用typename/class;也可以定义多个模板参数,用逗号隔开
模板非类型参数
//函数模板
template<typename T>//定义一个模板参数列表
//用T类型 定义具体的形参变量
bool compare(T a, T b)//compare是一个函数模板,compare+模板类型<> = 函数
{
cout << "template compare" << endl;
return a > b;
}
- 模板的实参推演
=》根据用户传入的实参类型,推出模板类型参数的具体类型
模板的实例化:在函数的调用点进行模板的实例化
模板函数:根据给定的类型 (compare(12, 24);)或 推导出的类型(compare(15, 35);),得到的实际的函数叫,模板函数,从而进行编译
/*
在函数调用点,编译器用用户指定的函数类型,从原来的模板实例化一份函数代码出来
//模板函数
bool compare<int>(int a, int b)
{
cout << "template compare" << endl;
return a > b;
}
bool compare<double>(double a,duoble b)
{
cout << "template compare" << endl;
return a > b;
}
*/
int main()
{
//函数调用点
compare<int>(12, 24);
compare<int>(11, 22);//此时不会在产生一个整型的模板函数,因为会造成函数的重定义,实际是直接调用原来生成的整型模板函数
compare<double>(12.0, 24.0);
//函数的实参推演
compare(15, 35);
注释里面的就是模板实例化在编译时的过程,总而言之,模板实例化是模板函数的过程,模板函数是模板实例化的结果。
现在这种传入相同类型的问题解决了,那传入不同类型参数呢?例如:
compare(28, 14.0);//没有与参数列表匹配的 函数模板“compare”实例,原因bool compare(T a, T b)
当如上定义时编译器会报错:没有与参数列表匹配的 函数模板“compare”实例,
原因 bool compare(T a, T b),传入的是两个相同类型的参数,而这里传入了不同类型。
此时有一种不是那么完善的改正方法,这种方法会使编译器提出警告,double 转换为 int型可能会照成数据丢失。
compare<int>(28, 14.0);//警告:数据丢失
除了上面这种情况外,还有一种传入字符串常量的情况,
compare("aaa", "bbb");
此时,对于某些类型来说,依赖编译器默认实例化的模板代码,代码的处理逻辑是错误的。编译器优先将compare处理为函数名,没有该函数,再去找compare的函数模板,这时编译运行都没有错,但是实际比较的是地址的大小,和我们的目标“比较ASCII码”不一致,所以针对这种情况,我们就引出了模板特例化的概念。
- 模板的特例化:
特殊的实例化(不是编译器提供的,而是用户提供的),编译器提供的模板函数不能满足我们的要求了,所以有了它。具体操作如下:
1、定义一个空的模板形参列表 :template<>;
2、定义一个自己想要定义的特殊的模板;
//针对compare函数模板,提供const char* 类型的特例化版本
template