c++ 模板

先介绍一个概念

泛型编程

泛型编程:编写与类型无关的逻辑代码,是代码复用的一种手段,模板是泛型编程的基础。

函数模板

函数模板:代表了一个函数家族,该函数与类型无关,在使用时被参数化,根据实参类型产生函数的特定类型版本。

函数模板的格式

template <typename Param1, typename Param2,...,class Paramn>
返回值类型 函数名(参数列表)
{
      ...
}

定义模板关键字

template <typename T>
T Add(T left, T right)
{
        return (left + right);
}
模板形参名字可以随意 命名,typename 是用来定义模板参数关键字,亦可以使用class。

注意:不能使用struct代替typename。

模板函数也可以定义为inline函数

注意:inline关键字必须放在模板形参表之后,返回值之前,不能放在template之前

模板是一个蓝图,它本身不是类或者函数,编译器用模板产生指定的类或者函数的特定类型版本,产生模板特定类型的过程称为函数模板实例化。

注意:模板被编译两次:

1.实例化之前,检查模板代码本身,查看是否出现语法错误,如:遗漏分号

2.在实例化之前,检查模板代码,查看是否所有的调用都有效,如:实例化类型不支持某些函数调用

【实参推演】

从函数实参确定模板形参类型和值的过程称为模板实参推演

多个类型形参的实参必须完全匹配

【类型形参转换】

一般不会转换实参以匹配已有的实例化,相反会产生新的实例。

编译器只会执行两种转换:

1.const转换:接收const引用或者const指针的函数可以分别用非const对象的引用或者指针来调用

2.数组或函数到指针的转换:如果模板形参不是引用类型,则对数组或函数类型的实参引用常规指针转换。数组实参将当做指向其第一个元素的指针,函数实参当做指向函数类型的指针。

模板参数

函数模板有两种类型参数:模板参数和调用参数

模板形参名字只能在模板形参之后到模板声或定义的末尾之间使用,遵循名字屏蔽规则

模板形参的名字在同一模板形参列表中只能使用 一次

所以模板形参前面必须加上class或者typename关键字修饰

注意:在函数模板的内部不能指定缺省的模板实参。

【非模板类型参数】

非模板类型形参是模板内部定义的常量,在需要常量表达式的时候,可以使用非模板类型参数

例如数组长度

类型等价性

模板形参说明

1.模板形参表使用<>括起来

2。和函数参数表一样,跟多个参数是必须用逗号隔开,类型可以相同也可以不相同

3.模板形参不能为空

4.模板形参可以是类型形参,也可以是非类型新参,类型形参跟在class和typename  后

5.模板类型实参可作为类型说明符用在模板中的任何地方,与内置类型或自定义类型使用方法完全相同,可用于指定函数形参类型、返回值、局部变量和强制类型转换

6.模板形参表中,class和typename具有相同的含义,可以互换,使用typename更加直观,但关键字typename是作为c++中的,旧的编译器可能不支持。

模板函数重载

注意:函数的所有重载版本的声明都应该位于该函数调用位置之前。

【说明】

1.一个非模板函数可以和一个同名的函数模板同时存在,而且该函数模板还可以被实例化为这个非模板函数。

2.对于非模板函数和同名函数模板,如果其他条件都相同,在调用时会优先调动非模板函数而不会从该模板产生出一个实例,如果模板可以产生一个具有更好匹配这个函数,那么将选择模板。

3.显示指定一个空的模板实参列表,该语法告诉编译器只有模板才能来匹配这个调用,而且所有函数模板参数都应该根据实参演绎出来。

4.模板函数不允许自动类型转换,但普通函数可以进行自动类型转换。

【模板函数特化】

有时候并不总是能够写出所由可能被实例化的类型都最适合的模板,在某些情况下,通用模板定义对于某个类型可能是完全错误的,或者不能编译,或者做一些错误的事情

模板函数特化形式如下:

1.关键字template后面接一对空的尖括号<>

2.再接模板名和一对尖括号,尖括号中指定这个特化定义的模板形参

3.函数形参表

4.函数体

只是定义了一个普通函数,该函数含有返回类型和与模板实例化相匹配的形参表。

注意:在模板特化版本函数的形参类型完全匹配,如果不匹配,编译器将为实参模板定义中实例化一个实例。

注意:特化不能出现在模板实例的调用之后,应该在头文件中包含模板特化的声明,然后使用该特化版本的每一源文件包含该文件。

模板类

【普通顺序表】

【模板类格式】

【模板类的实例化】

只要有一种不同的类型,编译器就会实例化出一个对应的类。

SeqList<int > sl1;

SeqList<double > sl2;

当 定义上述两种类型的顺序表时,编译器使用int 和double 分别代替模板形参,重新编写SeqList类,最后创建者名为SeqList<int >和SeqList<double >的类。

模板参数——实现容器适配器

模板的模板参数——容器适配器

非类型的类模板参数

注意:浮点数和类对象是不允许作为非类型模板参数的

类模板的特化

全特化

偏特化

模板的全特化和偏特化都是在已定义的模板基础之上,不能单独存在。

模板的分离编译

解决办法:

1.在模板头文件xxx.h里面显示实例化->模板类的定义后面添加template class SeqList<int >:一般不推荐这种方法,一方面老编译器可能不支持,另一方面实例化依赖调用者。(不推荐)

2.将声明和定义放到一个文件“xxx.hpp”里面,推荐使用这种方法。

模板总结

【优点】

模板复用了代码,节省资源,更快的迭代开发,c++的标准模板库(STL)因此而生。

增强了代码的灵活性。

【缺点】

模板让代码变得凌乱复杂,不易维护,编译代码时间变长。

出现模板编译错误时,错误信息非常凌乱,不易定位错误。


























  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值