C++泛型编程之函数模板【详细讲解】

1、定义函数模板

1)基本内容

  • 【值和类型是数据的两个主要的特征】,在【模板中数据的值和类型都被参数化了】。C++提供了两种模板机制,即【函数模板】【类模板】

  • 模板中的【类型参数】也称为【类属参数】

  • 模板的声明或者定义只能在【全局或者类范围】进行,不能在局部范围内进行

使用模板的目的在于让程序员能够编写与类型无关的代码【编写通用代码】

2)模板函数

定义一个函数模板后,当编译系统发现有一个对应的【函数调用时将根据实参中的类型来确认是否匹配函数模板中对应的类型形参】,然后生成一个重载函数。该重载函数的定义体和函数模板的定义体相同,称它为【模板函数】

3)函数模板与模板函数的区别

  • 函数模板是一个【模板】,其中用到【通用类型参数】,不能直接执行

  • 模板函数是一个【具体的函数】,它由编译系统在遇到具体的函数调用生成,【具有程序代码】,可以执行

  • 两者之间的关系

2、函数模板格式

1)格式

格式:template <class T> 或者 template <typename T>

这两种格式都可以定义函数模板和类模板,在使用上,两个没有明显的区别。

【潜规则:使用template <class T>来定义类模板,使用template <typename T>来定义函数模板】

2)【函数模板针对仅参数类型不同的函数;类模板针对仅成员属性和成员函数类型不同的类】

3)对格式的解释

template <class T> 或者 template <typename T>
名称解释
template声明创建模板(位置:位于函数模板或者类模板的紧跟上面)
typename/class后面的符号是一种数据类型
T通用数据类型,名称可以替换,通常为大写字母

4)举例

#include <iostream>

using namespace std;
//函数模板
template <typename TT,typename YY>
TT ADD(TT a, YY b)
{
	return a + b;
}

//编译器首先生成如下内容:模板函数
/******************************************
double ADD(double a,int b)  相当于TT = double ,YY = int 
{	
	return a+b;
}
int ADD(int a,int b) 相当于TT = int ,YY = int 
{
	return a+b;
}
*******************************************/
//然后再实现函数重载

int main()
{
	double A = 10.45;
	int B = 20;
	cout << ADD(A, B) << endl;
	cout << ADD(10, B) << endl;
	return 0;
}

运行结果:

30.45
30

 5)注意

  • 类型参数表中的参数必须是唯一的,而且至少要在函数体中出现一次,并且【不能出现类型参数名称重复】

  • template语句与函数模板声明之间【不能有其他语句】

  • 函数模板是一种特殊的函数,与普通函数的区别在于【类型被参数化】

3、使用函数模板的两种方式

 1)编译器自动推导

程序:

#include <iostream>

using namespace std;
//函数模板
template <typename TT>
TT ADD(TT a, TT b)
{
	cout << "调用了函数TT ADD(TT a, TT b)" << endl;
	return a + b;
}
template <typename TT,typename YY>
TT ADD(TT a, YY b)
{
	cout << "调用了函数TT ADD(TT a, YY b)" << endl;
	return a + b;
}
int main()
{
	int A = 10;
	int B = 20;
	cout << ADD(A, B) << endl;
	cout << ADD(10.12, 20.34) << endl;
	cout << ADD(20.34, A) << endl;
	return 0;
}

运行结果:

调用了函数TT ADD(TT a, TT b)
30
调用了函数TT ADD(TT a, TT b)
30.46
调用了函数TT ADD(TT a, YY b)
30.34

2)具体类型显示调用

程序:

#include <iostream>

using namespace std;
//函数模板
template <typename TT>
TT ADD(TT a, TT b)
{
	cout << "调用了TT ADD(TT a, TT b)" << endl;
	return a + b;
}
template <typename TT,typename YY>
TT ADD(TT a, YY b)
{
	cout << "调用了TT ADD(TT a, YY b)" << endl;
	return a + b;
}

int main()
{
	int A = 10;
	int B = 20;
	cout << ADD<int ,int>(A, B) << endl;  //注意:这里选择的依据是template这一行而不是TT ADD这一行;
	                                      //以这行程序为例,这里有两个int类型的参数,因此优先调用template中有两个参数的函数模板
	cout << ADD<double,double>(10.12, 20.34) << endl;
	cout << ADD<int>(20.34, A) << endl;
	return 0;
}

运行结果:

调用了函数TT ADD(TT a, YY b)
30
调用了函数TT ADD(TT a, YY b)
30.46
调用了函数TT ADD(TT a, TT b)
30

3)深入理解函数模板

  • 对于【函数模板中使用的类型不同,编译器会产生不同的函数】【发生函数重载】

  • 编译器会对函数模板进行两次编译

    • 第一次(模板定义)是对【函数模板本身进行编译】,包括语法检查等;【函数模板不是真正意义上的函数,需要转变为模板函数】

    • 第二次(模板实例化)是对【参数替换后的代码进行编译】,这与编译普通函数相同,进行类型规则检查等

4)注意:【使用编译器自动推导的方式时,函数模板是不允许隐式类型转换的,调用时类型必须严格匹配】

#include <iostream>

using namespace std;
//函数模板
template <typename TT>
TT ADD(TT a, TT b)
{
	cout << "调用了函数TT ADD(TT a, TT b)" << endl;
	return a + b;
}

int main()
{
	int A = 10;
	cout << ADD(20.34, A) << endl;  //这里出现问题,因为在编译器自动推导过程中,
	                                //编译器不知道TT到底是代指int类型的数据还是double类型的数据
	return 0;
} 

运行结果:

 4、调用规则

  • 如果普通函数和函数模板都可以实现,优先调用普通函数【因为函数模板编译过程分两步】

  • 可以通过空模板参数列表来强制调用函数模板

  • 函数模板可以进行重载

  • 如果函数模板比普通函数有更好的匹配优先调用函数模板

1)第一条实例

#include <iostream>

using namespace std;

template <typename TT>
TT ADD(TT a, TT b)
{
	cout << "TT ADD(TT a, TT b)" << endl;
	return a + b;
}
int ADD(int a, int b)
{
	cout << "int ADD(int a, int b)" << endl;
	return a + b;
}
int main()
{
	int A = 10;
	int B = 20;
	cout <<ADD(A, B) << endl;
	return 0;
}

运行结果:

int ADD(int a, int b)
30

2)第二条实例

#include <iostream>

using namespace std;

template <typename TT>
TT ADD(TT a, TT b)
{
	cout << "TT ADD(TT a, TT b)" << endl;
	return a + b;
}
int ADD(int a, int b)
{
	cout << "int ADD(int a, int b)" << endl;
	return a + b;
}
int main()
{
	int A = 10;
	int B = 20;
	cout <<ADD<>(A, B) << endl;
	return 0;
}

运行结果:

TT ADD(TT a, TT b)
30

3)第三条实例

#include <iostream>

using namespace std;

template <typename TT>
TT ADD(TT a, TT b)
{
	cout << "调用了TT ADD(TT a, TT b)" << endl;
	return a + b;
}
template <typename TT>  //发生了重载,参数列表不同
TT ADD(TT a, TT b, TT c)
{
	cout << "调用了TT ADD(TT a, TT b, TT c)" << endl;
	return a + b + c;
}

int main()
{
	int A = 10;
	int B = 20;
	cout << ADD(A, B) << endl;
	cout << ADD(A, B, 10) << endl;
	return 0;
}

运行结果:

调用了TT ADD(TT a, TT b)
30
调用了TT ADD(TT a, TT b, TT c)
40

4)第四条实例

#include <iostream>

using namespace std;

template <typename TT>            //函数模板比普通函数有更好的匹配,所以优先调用函数模板
TT ADD(TT a, TT b)               
{
	cout << "调用了TT ADD(TT a, TT b)" << endl;
	return a + b;
}
int ADD(int a, float b)
{
	cout << "int ADD(int a, float b)" << endl;
	return a + b;
}

int main()
{
	int A = 10;
	int B = 20;
	cout << ADD(A, B) << endl;
	return 0;
}

运行结果:

TT ADD(TT a, TT b)
30

  • 19
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值