一、函数模板
1、定义
建立一个通用函数,它所用到的数据的类型
(包括返回值类型、形参类型、局部变量类型)可以不具体指定,而是用一个虚拟的类型来代替
(实际上是用一个标识符来占位),等发生函数调用时再根据传入的实参来逆推出真正的类型。
2、举例
template<typename T> //T就是一个虚拟的类型,typename关键字也可以用class 关键字替换
bool compare(T a, T b)
{
cout << "template compare" << endl;
cout << typeid(T).name() << endl;
return a > b;
}
在函数模板中,数据的值和类型都被参数化了,
发生函数调用时编译器会根据传入的实参来推演形参的值和类型。
函数模板除了支持值的参数化,还支持类型的参数化。
3、多参数的函数模板
template<typename T1,typename T2>//模板说明的类型参数必须在函数定义中至少出现一次
void Fun(T1 a)
{
cout<<"aaa"<<endl;
}
5、类型参数和非类型参数
template<typename T,int b>//T为类型参数,b为非类型参数
该形参表示未知类型,如果是非类型形参,我们就知道它是一个未知值
6、模板参数应该注意的地方
- 模板形参遵循常规名字屏蔽规则。与全局作用域中声明的对象、函数或类型 同名的模板形参会屏蔽全局名字
typedef double T;
template <class T> T fun(const T &a, const T &b)
{
T tmp = a;
return tmp;
}
//将 T 定义为 double 的全局类型型别名将被名为 T 的类型形参所屏蔽,因 此,tmp 不是 double 型,相反,tmp 的类型是绑定到模板形参的任意类型。
- 用作模板形参的名字不能在模板内部重用。
template <class T> T calc(const T &a, const T &b)
{
typedef double T; // error: redeclares template parameter T
T tmp = a;
return tmp;
}
- 模板形参的名字只能在同一模板形参表中使用一次
template <class V, class V> V calc(const V&, const V&) ;
// error: illegal reuse of template parameter name V
二、模板函数
1、定义
模板函数的生成就是将函数模板的类型形参实例化
的过程。
2、举例
bool compare<int>(int a, int b)
{
cout << "template compare" << endl;
cout << typeid(int).name() << endl;
return a > b;
}
3、模板函数与函数重载的区别
模板函数类似于重载函数,但两者有很大区别:
函数重载时,每个函数体内可以执行不同的动作
但同一个函数模板实例化后的模板函数都必须执行相同的动作
三、模板函数的特例化
当我们定义的函数模板对于大多数的类型适用,但对于一些特殊函数尤其是字符串相关的一些操作时,就可能不太适用。因此,我们必须实现模板函数的特例化版本。
// compare char*类型的特例化版本
template<>
bool compare<char*>(char * a, char *b)
{
cout << "compare<char*>" << endl;
return strcmp(a, b);
}
template<>
bool compare<int>(int a, int b)
{
cout << "compare<int>" << endl;
return a > b;
}