57、深入理解函数模板

  • Post author:
  • Post category:其他



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 版权协议,转载请附上原文出处链接和本声明。