一、函数模板深入理解
1、编译器从函数模板通过具体类型产生不同的函数
2、编译器会对函数模板进行两次编译
(1)、对模板代码本身进行编译
(2)、对参数替换后的代码进行编译
3、函数模板本身不允许隐式类型转换
(1)、自动推导类型时,必须严格匹配
(2)、显示类型指定时,能够进行隐式类型转换
#include<iostream> using namespace std; template<typename T> T Max(T a, T b) { return a > b? a : b; } int main() { int a = 1; int b = 2; cout << "max is: " << Max(a, b) << endl; //cout << "max is: " << Max('a', b) << endl;//error, 自动推导时,必须严格匹配 cout << "max is: " << Max<char>('a', b) << endl;//right, 显示指定第一个参数, 可以进行隐式转换 return 0; }
函数模板的本质:
#include <iostream> #include <string> 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 //当编译到这行时,发生要用一个模板去初始化pi //而pi的类型又是void (FuncI)(int&, int&),所以 //此时,编译器会用int去替换T,然后生成一个Swap函数 //并把指针赋值给pi FuncD* pd = Swap;//编译器自动推导T为double,编译器生成另一个Swap函数 //以下证明pi与pd指向的是两个不同的函数 cout << "pi = " << reinterpret_cast<void*>(pi) << endl; cout << "pd = " << reinterpret_cast<void*>(pd) << endl; //发现两个地址不一样 //FuncT* pt = Swap; //编译器自动推导T为test。但是当进行T替换时 //由于Swap函数内部的T c = a;会调用Test的拷贝 //构造函数,但被我们故意设为private,所以编译 //出错,这个例子是用来说明会生成另一个不同的 //版本的Swap函数,在二次编译时发现错误 //cout << "pt = " << reinterpret_cast<void*>(pt) << endl; return 0; }
二、多参数函数模板
1、函数模板可以定义任意多个不同类型的参数
2、对于多参数模板
(1)、无法自动推导返回值类型(工程中将返回值参数作为第一个类型参数)
(2)、可以从左向右部分指定类型参数
#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和T3都是自动推导 cout << "result is: " <<Add<int>(2.3, 2) << endl;//4,有精度丢失 cout << "result is: " <<Add<float>(2.3, 2) << endl;//4.3
//T1 = double, T2 = int, T3自动推导 cout << "result is: " <<Add<double, int>(2.3, 2) << endl;//4
//T1 = int, T2 = double, T3 = float cout << "result is: " <<Add<int, double, float>(2.3, 2) << endl;//4 return 0; }
三、重载函数模板
1、c++编译器优先选择普通函数
2、如果模板可以产生一个更好的匹配,那么选择模板
3、可以通过空模板参数列表限定编译器只匹配模板
#include<iostream> 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 is: " << Max(a, b) << endl;//优先选择普通函数版本的 cout << "Max is: " << Max<>(a, b) << endl;//限定编译器只匹配函数模板 cout << "Max is: " << Max(1.0, 2.0) << endl;//函数模板能产生更好的,就不需要普通版本的来进行隐式类型转换了 cout << "Max is: " << Max('a', b) << endl;//函数模板只有一种类型的参数,本身不进行类型转换(不显示标识类型时),所以这里调用普通函数版的,并且进行隐式类型转换 cout << "Max is: " << Max<double>(a, b, 3) << endl; return 0; } //输出结果 /* int Max(int a, int b) Max is: 2 T Max(T a, T b) Max is: 2 T Max(T a, T b) Max is: 2 int Max(int a, int b) Max is: 97 T Max(T a, T b, T c) T Max(T a, T b) T Max(T a, T b) Max is: 3 */
四、小结
(1)、函数模板通过具体的类型产生不同的函数
(2)、函数模板可以定义任意多个类型不同的参数
(3)、函数模板中的返回值必须显示指定
(4)、函数模板可以像普通函数一样重载