C++函数模板

C++模板是泛型编程的基础,在C++中模板包括:

函数模板

定义一个函数的模板,编译器可根据传入参数的类型生成相应的函数,实现了写一个函数可适配不同输入参数。
模板对类型进行了参数化,提高了代码的通用型。

定义

 template <typenamne T>
 函数声明和定义

  • template — 声明创建模板
  • typename — 表明其后的符合是一种数据类型,和class等同
  • T — 通用数据类型的名称

使用

// 实现一个可交换两个参数的函数
template <typename T>  // 声明一个模板
void myswap(T & a, T & b)
{
	T temp;
	temp = a;
	a = b;
	b = temp;
}

函数模板的调用方式:

  • 自动类型推导
  • 显示类型指定

自动类型推导

T的类型由编译器根据传入的参数类型推导出,编译器根据推导出的类型在模板基础上来实现相应的函数。

void main()
{
	int a = 10;
	int b = 20;
	myswap(a, b);  //自动类型推导
	cout << "a = " << a << endl;
	cout << "b = " << b << endl;
}

显式类型指定

T的类型在调用时通过<类型>显式指定,编译器根据指定的类型在模板的基础上来实现相应函数

void main()
{
	int a = 10;
	int b = 20;
	myswap<int>(a, b);  //显式类型指定
	cout << "a = " << a << endl;
	cout << "b = " << b << endl;
}

使用注意事项

  • 自动类型推导必须推导出一致的数据类型T,才可以使用;
  • 模板必须确定T的数据类型,才可以使用;
  • 使用显式类型指定来调用模板是一个好的习惯 。
    示例:
void main()
{
	int a = 10;
	int b = 20;
	char c = 'f';
	//myswap(a, c);  //自动类型推导,不能使用
	// a、c类型不一致,对编译器来说有二义性
	// 编译器不能确定是根据a的类型还是根据b的类型来实现函数
	myswap<int>(a, c); //显示类型指定,可以使用
	// 这时编译器根据int类型实现函数,并对c进行隐式类型转换
	
}

示例

template <typename T>
void fun()
{
	cout << "test" << endl;
}

void main()
{
	//fun();  //不能使用
	// 还是一样的原因,编译器无法确定T的类型,不知道如何去实现相应的函数
	fun<int>(); // 可以使用
}

案例

  • 实现一个从大到小的排序的目标函数,实现对不同数据类型的数据进行排序
  • 使用选择排序来实现
template <typename T>  // 声明一个模板
void myswap(T & a, T & b)
{
	T temp;
	temp = a;
	a = b;
	b = temp;
}

// 选择排序模板函数
template <typename T>
void selectionSort(T array[], int len)
{
	int max;
	for (int i = 0; i < len; i++)
	{
		max = i;  // 假设未排序元素第一个位置为最大元素
		for (int j = i; j < len; j++)
		{
			if (array[j] > array[max])
				max = j;
		}
		if (max != i)  // 最大元素未在正确位置
		{
			myswap<T>(array[i], array[max]);
		}
	}
}

// 打印数组模板模板函数
template <typename T>
void printArray(T array[],int len)
{
	for (int i = 0; i < len; i++)
	{
		cout << array[i] << " ";
	}
	cout << endl;
}

void main()
{
	// 测试函数模板排序
	int intArray[] = { 4, 5, 6, 3, 6, 10, 75 };
	selectionSort<int>(intArray, 7);
	printArray<int>(intArray, 7);

	char charArray[] = {"dfeegegd"};
	selectionSort<char>(charArray, 7);
	printArray<char>(charArray, 7);
}

函数模板和普通函数的区别

主要是隐式类型转换上

  • 普通函数在调用时是可以进行隐式类型转换的;
  • 函数模板,使用自动推导类型不可以进行隐式类型转换(根本原因还是编译器不知道如何实现函数,对照使用注意事项内容);
  • 函数模板,使用显式类型指定,可以进行隐式类型转换。

结论:在使用函数模板时,建议使用显式类型指定来调用,即可以避免一些问题,也增加了程序的可读性。

函数模板和普通函数调用规则

  • 如果调用时,普通函数和函数模板都可以匹配,则调用普通函数
  • 可以通过空模板参数强制调用普通函数
  • 函数模板也可以进行重载
  • 如果函数模板比普通函数更加匹配,则调用函数模板
    实例:
//普通函数
void myPrint(int a)
{
	cout << "调用普通函数" << endl;
}

//模板函数
template <typename T>
void myPrint(T a)
{
	cout << "调用模板函数" << endl;
}

//模板函数重载
template <typename T>
void myPrint(T a, T b)
{
	cout << "调用重载模板函数" << endl;
}

void mian()
{
	int a = 10;
	int b = 20;
	char c = 'c';
	myPrint(a);  //普通函数和模板函数都匹配,调用普通函数
	myPrint<>(a);  // 通过空模板参数强制调用模板函数
	myPrint(a,b);	// 调用重载模板函数
	myPrint(c); // 函数模板更匹配,调用函数模板
}

建议:定义了函数模板,就不用再去定义相应的普通函数了,容易使代码可读性变差。

函数模板的局限性

  • 自定义类型如果没有定义相应运算符操作,则程序不知道如何对自动义类型进相应操作,程序报错
    实例:
// 定义一个person类
class person {
public:
	person(string name, int age) {
		this->mName = name;
		this->mAge = age;
	}
	string mName;
	int mAge;
};

//定义一个比较函数模板
template <class T>
bool myCompare(T a, T b)
{
	if (a == b)
		return true;
	else
		return false;
}
//函数模板具体化
template <>
bool myCompare(person a, person b)
{
	if ((a.mName == b.mName) && (a.mAge == b.mAge))
		return true;
	else
		return false;
}

void mian()
{
	person p1("aimi", 10);
	person p2("tomi", 10);
	bool res = myCompare(p1,p2);  // 不可以直接使用,编译时报错,实现模板具体化后则可常使用
	//解法方法
	// 1、对自定义类型实现操作符重载
	// 2、对类模板实现具体化,程序优先调用具体化的模板
	if(res)
		cout << "p1 == p2"  << endl;
	else
	 	cout << "p1 != p2"  << endl;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值