上一节我们对函数模板有了具体的了解,这节我们在深入的了解一下函数模板
一、函数模板的本质
1、编译器从函数模板通过具体类型产生不同的函数
2、 编译器会对函数模板进行两次编译
- 对模板代码本身进行编译
- 对参数替换后的代码进行编译(即调用时)
示例:函数模板的本质
#include <iostream>
using namespace std;
class Test
{
Test(const Test&);
public:
Test()
{
}
};
template<typename T>
void Swap(T& a,T& b)
{
T c = a;
a = b;
b = c;
}
typedef void (FuncI)(int&,int&);
typedef void (FuncD)(double&,double&);
typedef void (FuncT)(Test&,Test&);
int main()
{
FuncI* pi = Swap; //编译器自动推导T为int
FuncD* pd = Swap; //编译器自动推导T为double
//FuncT* pt = Swap; //编译器自动推导T为Test,如果加上这行代码会错。因为拷贝构造函数是私有的
// 在这里就能体现出编译器的二次编译
cout << "pi = " << reinterpret_cast<void*>(pi) << endl;
cout << "pd = " << reinterpret_cast<void*>(pd) << endl;
//cout << "pt = " << reinterpret_cast<void*>(pt) << endl;
return 0;
}
打印结果
通过打印指针的地址我们就可以看到这是两个不同的函数。
二、多参数函数模板
1、函数模板可以定义任意多个不同的类型参数
template
<typename T1,typename T2,typename T3>
T1 add(T2 a,T3 b)
{
return static_cast<T1>(a+b);
}
2、对于多参数模板
(1)无法自动推导返回值类型
(2)可以从左到右部分指定类型参数
//T1=int T2=double T3=double
int r1 = add<int>(0.5,0.8);
//T1=int T2=float T3=double
int r2 = add<int,float>(0.5,0.8);
//T1=int T2=float T3=float
int r3 = add<int,float,float>(0.5,0.8);
在工程中如果返回值为泛指类型,我们就将返回值参数作为第一个类型参数,推荐第一种写法。
示例:多参数函数模板
#include <iostream>
using namespace std;
template
<typename T1,typename T2,typename T3>
T1 add(T2 a,T3 b)
{
return static_cast<T1>(a+b);
}
int main()
{
//T1=int T2=double T3=double
int r1 = add<int>(0.5,0.8);
//T1=double T2=float T3=double
double r2 = add<double,float>(0.5,0.8);
//T1=float T2=float T3=float
float r3 = add<float,float,float>(0.5,0.8);
cout << "r1 =" << r1 << endl;
cout << "r2 =" << r2 << endl;
cout << "r3 =" << r3 << endl;
return 0;
}
打印结果
这个示例告诉我们工程中一定要将返回值参数作为第一个类型参数
三、有趣的问题
当函数重载遇见函数模板会发生什么?
函数模板可以像普通函数一样被重载
- C++编译器会优先考虑普通函数
- 如果函数模板可以产生一个更好的匹配,那么选择模板
- 可以通过空模板实参列表限定编译器只匹配模板
int r1 = Max(1,2);
double r2 = Max<>(0.5,0.8); //限定编译器只选择模板
示例:重载函数模板
#include <iostream>
#include <string>
using namespace std;
template < typename T >
T Max(T a, T b)
{
cout << "T Max(T a, T b)" << endl;
return a > b ? a : b;
}
int Max(int a, int b)
{
cout << "int Max(int a, int b)" << endl;
return a > b ? a : b;
}
template < typename T >
T Max(T a, T b, T c)
{
cout << "T Max(T a, T b, T c)" << endl;
return Max(Max(a, b), c);
}
int main()
{
int a = 1;
int b = 2;
cout << Max(a, b) << endl; // 普通函数 Max(int, int)
cout << Max<>(a, b) << endl; // 函数模板 Max<int>(int, int)
cout << Max(3.0, 4.0) << endl; // 函数模板 Max<double>(double, double)
cout << Max(5.0, 6.0, 7.0) << endl; // 函数模板 Max<double>(double, double, double)
cout << Max('a', 100) << endl; // 普通函数 Max(int, int)
return 0;
}
注意:函数模板本身不允许隐示类型转换
小结
- 函数模板通过具体类型产生不同的函数
- 函数模板可以定义任意多个不同的类型参数
- 函数模板的返回值类型必须显示指定
- 函数模板可以向普通函数一样被重载