1、模板函数与函数模板的区别
模板函数:根据模板写出来的函数。
函数模板:以后函数实例化都是根据这个模板进行的。
#include <iostream> using namespace std; // T Max(T a, T b) 函数模板 template<typename T> T Max(T a, T b) { return a > b ? a : b; } int main() { cout<<Max<int>('a', 8)<<endl; // Max<int>('a', 8) 模板函数 cout<<Max(7, 8)<<endl; // Max(7, 8) 模板函数 return 0; }
2、函数模板深入理解
(1)编译器从函数模板通过不同类型产生不同函数
(2)编译器会对函数模板进行两次编译
[1] 对模板代码本身进行编译
[2] 对参数替换后的代码进行编译
(3)注意事项
[1] 函数模板本身不允许隐式类型转换
[2] 自动推导类型时,必须严格匹配
[3] 显式类型指定时,能够进行隐式类型转换
#include <iostream> using namespace std; template<typename T> T Max(T a, T b) { return a > b ? a : b; } int main() { cout<<Max(7, 8)<<endl; // 可自动推导类型为int cout<<Max<int>('a', 8)<<endl; // 两个参数的类型不同,不要隐式转换为int,因为函数模板不允许隐式转换 return 0; }
3、函数模板的本质
#include <iostream> #include <string> using namespace std; class Test { private: Test(const Test&) {} public: Test() {} }; template <typename T> void Swap11(T& a, T &b) { T c = a; a = b; b = c; } typedef void (FuncA) (int&, int&); typedef void (FuncB) (double&, double&); typedef void (FuncC) (Test&, Test&); int main() { /* 解析: FuncA * pa = Swap11; 编译器自动推导T为int 用模板Swap11去出师Pa pa的类型又是 void (FuncA) (int&, int&); 因此,编译器会用int去替换T,然后生成一个Swap函数 并把指针赋值给pa FuncB * pb = Swap11; 编译器自动推导T为double FuncC * pc = Swap11; 编译器自动推导T为test,但是进行T替换时, 由于Swap函数内部的T c = a; 会调用Test的拷贝构造函数Test(const Test&) {} 但它是私有的,所以编译会出错 */ FuncA * pa = Swap11; FuncB * pb = Swap11; // 证明pa与pb是不同的两个函数 cout<<"pa= "<<reinterpret_cast<void*>(pa)<<endl; cout<<"pb= "<<reinterpret_cast<void*>(pb)<<endl; //FuncC * pc = Swap11; //cout<<"pc= "<<reinterpret_cast<void*>(pc)<<endl; return 0; }
4、函数模板多参数
特点:
【1】无法自动推导返回值类型;
【2】可以从左向右部分指定类型参数;
【3】工程中将返回值参数作为第一个类型参数;
#include <iostream> #include <string> using namespace std; template <typename T1, typename T2, typename T3> T1 Add(T2 a, T3 b) { cout<<"T1= "<<a<<endl; cout<<"T2= "<<b<<endl; return static_cast<T1>(a); } int main() { // T1 = <int> = int , T2 = 0.9 = double , T3 = 0.8 = double // <int> 从左向右指定类型(返回值->参数1->参数2) 未指定到的, 自动推导类型 int a = Add<int>(0.9, 0.8); cout<<"返回结果为 "<<a<<endl; // T2 = <double> = double, T2 = 10 = int, T3 = 1.9 = double double b = Add<double, char>('b', 91.2); cout<<"返回结果为 "<<b<<endl; // T3 = <char> = char, T2 = 90 = int, T3 = 9.8 = float char c = Add<char, int, float>(90, 9.8); cout<<"返回结果为 "<<c<<endl; return 0; }
5、函数模板重载
【1】优先匹配普通函数,其次匹配函数模板
【2】如果函数模板可以产生一个更好的匹配,那么选择模板
【3】可以通过空模板实参列表,限定只匹配模板
int a = Max(1,2); // 优先匹配普通函数
int b = Max<>(1,2); // <>空模板实参列表,只能匹配函数模板
#include <iostream> #include <string> using namespace std; template <typename T> T Max(T a, T b) { cout<<"函数模板"<<endl; return a>b?a:b; } int Max(int a, int b) { cout<<"普通函数"<<endl; return a>b?a:b; } template <typename T> T Max(T a, T b, T c) { cout<<"---函数模板---"<<endl; return Max(Max(a, b), c); } int main() { int a = 10; int b = 88; cout<<Max(a, b)<<" "; cout<<Max<>(a, b)<<" "; // <>限定只能从函数模板去匹配 cout<<Max(3.8, 4.1)<<" "; cout<<Max(3.8, 4.1, 8.8)<<" "; // 参数个数匹配 cout<<Max('u', 8.8)<<" "; // 不允许隐式转换,所以不会匹配函数模板 return 0; }
6、总结
(1)函数模板通过具体类型产生不同的函数
(2)函数模板可以定义任意多个不同的类型参数
(3)函数模板中的返回值类型必须是显示指定
(4)函数模板可以像普通函数一样重载