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)<<"\n\n";
cout<<Max<>(a, b)<<"\n\n"; // <>限定只能从函数模板去匹配
cout<<Max(3.8, 4.1)<<"\n\n";
cout<<Max(3.8, 4.1, 8.8)<<"\n\n"; // 参数个数匹配
cout<<Max('u', 8.8)<<"\n\n"; // 不允许隐式转换,所以不会匹配函数模板
return 0;
}
6、总结
(1)函数模板通过具体类型产生不同的函数
(2)函数模板可以定义任意多个不同的类型参数
(3)函数模板中的返回值类型必须是显示指定
(4)函数模板可以像普通函数一样重载