C++泛型编程(上) 函数模板

一、函数模板

C++提供了函数模板,通过函数模板建⽴⼀个通⽤函数,其函数类型和形参类型不具体制定,⽤⼀个虚拟的类型来代表,这个通⽤函数就成为函数模板。

  • 凡是函数体相同、类型不同的函数都可以⽤这个模板代替,不必定义多个函数,只需在模板中定义⼀次即可。
  • 在调⽤函数时系统会根据实参的类型来取代模板中的虚拟类型,从⽽实现不同函数的功能。

写两个demo展示一下非模板函数与模板函数的区别

int  my_min(int  a,  int  b){
	return  a  >  b  ?  a  :  b;
}
double  my_min(double  a,  double  b){
	return  a  >  b  ?  a  :  b;
}
void  test(){
	//  1.  int  类型
	int  a  =  10;
	int  b  =  20;
	int  min_int_val  =  min(a,  b);
	//  2.  double  类型
	double  a  =  6.66;
	double  b  =  8.88;
	double  min_double_val  =  min(a,  b);
}

缺点一幕了然 参数是固定的,如果想加入别的参数只能进行重载 非常麻烦,复用性几乎为零

template<class  T>
T  my_min(T a,  T b){
	return  a  >  b  ?  a  :  b;
}
void  test(){
	//  1.  int  类型
	int  ia  =  10;
	int  ib  =  20;
	int  min_int_val  =  my_min(ia,  ib);
	cout  <<  "min_int_val:"  <<  min_int_val   <<  endl;
	//  2.  double  类型
	double  da  =  6.66;
	double  db  =  8.88;
	double  min_double_val  =  my_min(da,   db);
	cout  <<  "min_double_val:"  <<  min_double_val   <<  endl;
	//  3.  char  类型
	char  a  =  'c';
	char  b  =  'd';
	char  min_char_val  =  my_min(a,  b);
	cout  <<  "min_char_val:"  <<  min_char_val   <<  endl;
}

二、模板细节

1、class和typename区别

定义模板参数时,使⽤class 和 typename 等价,但 typename  在模板中也有其他的⽤途。
template<class  T>
T  min(T  a,  T  b){
	return  a  >  b  ?  a  :  b;
}
template<typename  T>
T  min(T  a,  T  b){
	return  a  >  b  ?  a  :  b;
}

2、模板参数

1.  模板参数可以多个。
2.  模板既可以是类型、也可以是编译期常量。
3.  模板参数可以有默认值。
template<class  T1,  class  T2>
T1  my_min(T1  a,  T2  b){
	return  a  >  b  ?  a  :  b;
}
template<class  T=int>
T  my_max(T  a,  T  b){
	return  a  >  b  ?  a  +  N   :  b  +  N;
}
template<class  T,  int  N>
T  my_equal(T  a,  T  b){
	return  (a  ==  b)  ?  (a  +   N)  :  (b  +  N);
}
void  test()
{
	int  a  =  10;
	int  b  =  20;
	int  ret  =  my_equal<int,  100>(a,   b);
	cout  <<  "ret:"  <<  ret  <<   endl;
}

3、模板类型自动推导

函数模板的类型是调⽤时根据参数的类型⾃动推导出来的,类型推导仅限于函数模板,对于类模板是
不能够进⾏⾃动类型推导的。
template<class  T>
T  my_min(T  a,  T  b){
	return  a  >  b  ?  a  :  b;
}
void  test()
{
	//  1.  int  类型
	int  ia  =  10;
	int  ib  =  20;
	int  min_int_val  =  my_min(ia,  ib);
	cout  <<  "min_int_val:"  <<  min_int_val   <<  endl;
	//  2.  double  和  int  类型
	double  da  =  30;
	//  my_min(ia,  da);
}

4、函数模板重载

函数模板也和普通函数⼀样⽀持重载,重载的条件和普通函数⼀样:
1.  同⼀个作⽤域
2.  参数个数不同
3.  参数类型不同
4.  参数顺序不同
template<class  T>
T  my_min(T  a,  T  b){
	return  a  >  b  ?  a  :  b;
}
template<class  T>
T  my_min(T  a,  T  b,  T  c){
	return  a  >  b  ?  a  :  b;
}

5.函数模板和普通函数调⽤规则

1.  C++编译器优先匹配普通函数。
2.  通过模板空实参数指定编译器只能匹配函数模板。
3.  如果函数模板可以产⽣⼀个更好的匹配,那么选择模板。
template<class  T>
T  my_min(T  a,  T  b){
	return  a  >  b  ?  a  :  b;
}
int  my_min(int  a,  int  b){
	return  a  >  b  ?  a  :  b;
}
void  test(){
	//  1.  匹配普通函数
	int  ia  =  10;
	int  ib  =  20;
	int  min_int_val  =  my_min(ia,  ib);
	//  2.  匹配函数模板
	int  ret  =  my_min<>(ia,  ib);
	//  3.  匹配函数模板
	char  a  =  'c';
	char  b  =  'd';
	char  min_char_val  =  my_min(a,  b);
}

6、函数模板和普通函数区别

1.  普通函数⽀持隐式类型转换。
2.  ⾃动类型推导,不⽀持隐式类型转换。
3.  显式指定模板参数类型,⽀持隐式类型转换。
template<class  T>
T  my_min(T  a,  T  b){
	return  a  >  b  ?  a  :  b;
}
int  my_min(int  a,  char  b){
	return  a  >  b  ?  a  :  b;
}
void  test()
{
	int  a  =  10;
	char  b  =  'c';
	//  1.  匹配普通函数
	my_min(a,  b);
	//  2.  匹配函数模板
	my_min<int>(a,  b);
}

模板的编译机制

C++并不是把函数模板当成能够处理任何类型的函数,函数模板根据具体的调⽤情况,产⽣出对应的具体的函数版本,供程序调⽤。
函数模板编译机制:
我们将第⼀个例⼦中的程序进⾏编译,编译后根据实际调⽤情况⽣成以下三个函数,分别对应
int 、 double 、 char 类型的版本

_Z6my_minIiET_S0_S0_
_Z6my_minIdET_S0_S0_
_Z6my_minIcET_S0_S0_
函数模板和普通函数共存:
1.  如果普通函数能够匹配调⽤,编译器不会再⽣成模板函数。
2.  当调⽤函数时通过空参数列表强制匹配函数模板,此时编译器会再根据函数模板产⽣⼀个模板函
数。
template<class  T>
T  my_min(T  a,  T  b){
	return  a  >  b  ?  a  :  b;
}
int  my_min(int  a,  int  b){
	return  a  >  b  ?  a  :  b;
}
void  test()
{
	//  1.  int  类型
	int  ia  =  10;
	int  ib  =  20;
	int  min_int_val  =  my_min(ia,  ib);
	cout  <<  "min_int_val:"  <<  min_int_val   <<  endl;
	int  ret  =  my_min<>(ia,  ib);
	//  2.  double  类型
	double  da  =  6.66;
	double  db  =  8.88;
	double  min_double_val  =  my_min(da,   db);
	cout  <<  "min_double_val:"  <<  min_double_val   <<  endl;
	//  3.  char  类型
	char  a  =  'c';
	char  b  =  'd';
	char  min_char_val  =  my_min(a,  b);
	cout  <<  "min_char_val:"  <<  min_char_val   <<  endl;
}
代码编译过后会生成4个函数
_Z6my_minii
_Z6my_minIiET_S0_S0_
_Z6my_minIdET_S0_S0_
_Z6my_minIcET_S0_S0_

模板的独立编辑问题

1.独⽴编译即 C++编译器编译  a.cpp时,并不知道  b.cpp中定义了哪些符号,当链接时,如果发现
其他 cpp中没有定义则会报错:  ⽆法链接的外部符号  。
2.  编译器会对函数模板进⾏两次编译,在声明的地⽅对模板代码本身进⾏编译,在调⽤的地⽅对参
数替换后的代码进⾏编译。
这会导致模板分⽂件编写时的⼀些问题:

具体demo不再书写,只要记住,大部分情况下模板声明和实现在一个文件内即可。后缀为**.hpp**

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值