1、函数模板深入理解
— 编译器从函数模板通过具体类型产生不同的函数
— 编译器会对函数模板进行两次编译
1、对模板代码本身进行编译
2、对参数替换后的代码进行编译
-
注意事项:
函数模板本身不允许隐式类型转换
1、自动推导类型时,必须严格匹配
2、显示类型指定时,能够进行隐式类型转换(最后一个程序我会证明)
程序1:证明编译器会对函数模板进行两次编译
#include <iostream>
#include <string>
using namespace std;
class Test
{
Test(const Test& obj);
public:
Test()
{
}
};
template<typename T>
void Swap(T& a, T& b)
{
T c = a;
a = b;
b = c;
}
typedef void (FuncI)(int&, int&); //重命名了函数类型,必须通过指针指向某个函数才能有效编译器自动推导 T 为 int
typedef void (FuncD)(double&, double&); //编译器自动推导 T 为 double
//typedef void (FuncT)(Test&, Test&); //拷贝构造函数为private,17行代码不能进行拷贝构造
int main()
{
FuncI* pi = Swap;
FuncD* pd = Swap;
// FuncT* pt = Swap;
cout << "pi = " << reinterpret_cast<void *>(pi) << endl; //重解释为void *类型
cout << "pd = " << reinterpret_cast<void *>(pd) << endl;
// cout << "pt = " << reinterpret_cast<void *>(pt) << endl;
return 0;
}
分析:首先对模板代码本身进行编译这是肯定的,如果对参数替换后的代码不进行编译,那么我们所输出的指针地址都是同一个值,因此编译器会对函数模板进行两次编译,且编译器会自动推导 T 的类型。
2、多参数函数模板
- 函数模板可以定义任意多个不同的类型参数
template<typename T1, typename T2, typename T3>
T1 Add(T2 a,T3 b)
{
return static_cast<T1>(a + b);
}
int r = Add<int, float, double>(0.5, 0.8);
-
对于多参数模板
— 无法自动推导返回值类型
— 可以从左向右部分指定类型参数
//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);
工程中将返回值参数作为第一个类型参数!其余的参数 编译器可以自己去推导,一般遇见小数,编译器默认为 double 类型
#include <iostream>
#include <string>
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;
}
分析:这个程序主要是告诉我们多参数模板的使用,以及前面提到的一点,显示类型指定时,能够进行隐式类型转换。
返回值参数作为第一个类型参数,必须显示指定
,其余的参数无所谓。
3、重载函数模板
当函数重载遇见函数模板会发生什么?
-
函数模板可以像普通函数一样被重载
— C++编译器
优先考虑普通函数
— 如果函数模板可以产生一个更好的搭配,那么选择模板
— 可以通过
空模板实参列表
限定编译器只匹配模板
#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 << endl; //普通函数
cout << Max<>(a, b) << endl << endl; //模板函数,空模板实参列表强制调用模板函数
cout << Max(3.0, 4.0) << endl << endl; //模板函数
cout << Max(5.0, 6.0, 7.0) << endl << endl; //模板函数
cout << Max('A', 10) << endl << endl; //普通函数,参数可以进行隐式类型转换,函数模板本身不允许隐式类型转换,所以调用普通函数
cout << Max<int>('A', 10) << endl << endl; //强制调用模板函数,'A'会隐式类型转换成int类型,也就是ASCII数值65
//显示类型指定时,能够进行隐式类型转换(在这里证明)
return 0;
}
小结
:
- 函数模板通过具体类型产生不同的函数
- 函数模板可以定义任意多个不同类型参数
- 函数模板中的返回值必须显示指定
- 函数模板可以像普通函数一样被重载
版权声明:本文为xiebs原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。