一、泛型编程
泛型编程是指编写与数据类型无关的代码。不需要编程者为每种数据类型编写专门的代码,编译器会使用模板根据不同的数据类型产生对应的数据类型相关的代码。这样不仅可以提高代码的重用性,还可以提高代码的灵活性和安全性。
泛型编程是一种编程范式,而模板是实现泛型编程的一种具体机制。模板包括函数模板与类模板。
二、函数模板
函数模板定义了一个独立于类型的函数框架,其中函数参数的类型和返回值的类型都是未指定的,而是用模板参数来表示。
- 必须确定参数类型才可使用函数模板。
1、定义
<>括号中为模板参数列表,模板定义中,模板参数列表不能为空。
template :声明创建模板的关键字。
typename :模板类型参数,也可以用class关键字,可以互换,只是习惯问题。
T :通用的数据类型,名称可以替换,通常为大写字母
#include<iostream>
using namespace std;
template<typename T>
void swap(T& a, T& b) {
T tmp = a;
a = b;
b = tmp;
}
2、auto在模板里的使用
- 从C++14开始,
auto
可以用作返回类型,允许编译器根据函数的返回语句自动推导返回类型。 - 可以定义自动推导的变量
- 在模板函数的参数列表中,
auto
不能直接用作参数类型,因为模板参数在编译时需要明确的类型信息来实例化模板。
3、实例化
函数模板本身并不是一个函数,编译器会通过传入的不同的参数实例化对应的参数函数类型
3.1隐式实例化
编译器根据传入的实参类型来推演实例化函数的对应类型,称为隐式实例化
- 普通函数可以进行隐式类型转换,但是函数模板隐式实例化不可进行隐式类型转换
- 必须推导出一致的通用数据类型才能实例化函数模板
3.2显示实例化
在函数名后面加上<类型>即可指定模板参数的实际类型
- 显式实例化可以隐式类型转换参数类型
4、与普通函数的调用规则
- 一个非模板函数可以和一个同名的函数模板同时存在,而且该函数模板还可以被实例化为这 个非模板函数 。如果其他条件都相同,在调动时会优先调用非模板函数而不会从该模板产生出一个实例。
- 如果模板可以产生一个具有更好匹配的函数, 那么将选择模板
- 可以通过空模板参数列表来强制调用函数模板
三、类模板
1.定义
template<class T1, class T2, ..., class Tn>
class 类模板名
{
// 类内成员定义
};
2、实例化
类模板没有隐式实例化,类模板实例化需要在类模板名字后跟<>,然后将实例化的类型放在<>中即可,类模板名字不是真正的类,而实例化的结果才是真正的类。
类模板在模板参数列表中可以有默认参数,但是不能在模板外部的类模板成员的定义上指定默认模板参数。
3、成员函数的声明与定义分离
- 在类外定义类模板中的函数时,作用域限定符前不能只用类名,而是要用类型,并且加上模板参数和声明
- 模版不建议声明和定义分离到两个文件.h 和.cpp会出现链接错误