15.1 模板概念与函数模板的定义、调用

一:概述

vector:vector
几句话
<1>所谓泛型编程,是以独立于任何特定类型的方式编写代码。使用泛型编程时,我们需要提供具体程序实例所操作的类习惯或者值;
<2>模板是泛型编程的基础。模板是创建类或者函数的蓝图或公式,我们给这些蓝图或者公式提供足够的信息,让这些蓝图或者公式真正的转变为具体的类或者函数,这种转变发生在编译时;
<3>模板支持将类型作为参数的程序设计方式,从而实现了对泛型程序设计的直接支持。也就是说,C++模板机制允许在定义类、函数时将类型作为参数。

模板一般分为函数模板和类模板 本节课主要讲函数模板

二:函数模板的定义

<1>模板定义是用template关键字开头,后面跟<>,<>里面叫模板参数列表(模板实参),如果模板参数列表里面有多个参数,则用逗号分开。
<>里面必须至少得有一个模板参数,模板参数前面有个typename/class(不是用来定义类的)关键字。
template 这种写法大家硬记。
如果模板参数列表里面有多个模板参数,那你就要用多个typename/class: <typename T,typename Q>
<2>模板参数列表里面表示在函数定义中要用到的"类型"或者"值",也和函数参数列表类似。那我们用的时候,有的时候得指定模板实参给它,指定的时候我们要用<>把模板实参包起来,有的时候又不需要指定模板实参给它,系统自己能够根据一些信息推断出来,后续我们会举例;
<3>funcadd这个函数声明了一个名字为T的类型参数。这里注意:T实际是类型,这个T到底代表的是啥类型,编译器在编译的时候会根据针对funcadd()的调用来确定。

三:函数模板的使用

函数模板调用和函数调用区别不大,调用的时候,编译器会根据你调用这个函数模板时的实参去推断模板参数列表里的参数(形参)的类型。大家一定要注意措辞:模板参数有时候是推断出来的(有的时候是需要你提供),推断的依据是什么呢? 是根据你调用这个函数的实参来推断的。
当然有的时候,光凭借函数实参是推断不出来模板参数,这个时候就要用<>来主动的提供模板参数了。

template<typename T>
T funcadd(T a, T b);

int he = funcadd(3, 1);  //3,1 系统认为是int,所以编译器能够推断出来的模板形参是个int型,也就是说这个参数T是int型;
cout << he << endl;
//编译器在推断出来这个模板的形参类型之后,编译器就为我们实例化一个特定版本的函数。
double he2 = funcadd(3.1f, 1.2f);
cout << he2 << endl;
double he3 = funcadd(3, 1.2f);  //报错,系统不知道该推断成int还是idouble;单模板参数

四:非类型模板参数

因为T前面有个typename/class,这表示T代表一个类型,是一个类型参数。
那么在模板参数列表里边,还可以定义非类型参数; 非类型参数代表的是一个值。
既然非类型代表一个值,那么肯定不能用typename/class这种关键字来修饰这个值。
我们当然要用以往学习过的传统类型名来指定非类型参数了。比如你非类型参数S如果是个整型, int S。

template<typename T, int S>
T funcadd(T a, T b);

当模板被实例化时,这种非类型模板参数的值或者用户提供的,或者是编译器推断的,都有可能。
但是,这些值必须都得是常量表达式,因为实例化这些模板是编译器在编译时实例化的。
std::cout << funcadd2<12, 13>() << endl; // 显示的指定模板参数 在<>中提供额外的信息

template<int a, int b>
int funcadd2()
funcadd2(3, 5);  //错误
int result = funcadd2<12, 13>();  //显式的指定模板参数--在尖括号中提供额外的信息。
int a = 12;
int result = funcadd2<a, 13>();  // 这不可以,值必须是在编译的时候就能够确定,因为实例化函数模板是在编译的时候干的事情。
int result = funcadd3<int, 11, 12>(13);
cout << result << endl;
int result2 = funcadd3<double, 11, 12>(13);  // 系统会以我们用<>传递的类型为准,而不是用13来推断什么类型。
const char(&p1)[5] = "test";

int result3 = charscomp("test", "test1");  // 没有提供非类型模板参数,系统会根据字符串(test2)(还有\0)的长度6个, test长度5个,取代L1,L2;
cout << result3 << endl;

模板定义并不会导致编译器生成代码,只有在我们调用这个函数模板时,
使编译器为我们实例化了一个特定版本的函数之后,编译器才会生成代码
编译器生成代码的时候,需要能够找到函数的函数体,所以函数模板的定义通常都是在.h文件中。

template<unsigned L1, unsigned L2>  // 本例中仍旧没有类型参数,只有非类型模板参数
inline  // 模板函数可以是inline的,inline的位置放在模板参数列表之后,
int charscomp(const char(&p1)[L1], const char(&p2)[L2])
{
	return strcmp(p1, p2);
}

//int charscomp(const char(&p1)[5], const char(&p2)[6])
//{
//	return strcmp(p1, p2);
//}

int main()
{
	int result = charscomp("test2", "test");
	cout << result << endl;
	cin.get();
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值