深入解析C++模板:从基础到高级应用
1.函数模板
1.1.函数模板的使用
基本语法:
有两种:class和typaname
代码示例:
此时T 就可以进行识别 传过来的类型是int类型还是int类型
但是此时不可以一个传int类型一个传double类型,此时无法识别到底是声明类型
此时就可以引入两个 泛型参数,此时两个形参互不干扰
1.2.函数模板的实例化
函数模板的实例化:
1.隐式实例化
隐式实例化时编译器,编译器最常见的实例化方式,当调用函数模板的时候,泛型参数会依据传入的参数自动识别,推断函数模板的类型
2.显示实例化
显示实例化直接指定函数模板的参数,也分为两种情况
1.确定函数模板的参数
在全局变量中,进行显示初始化
2.不确定函数模板的参数
在传参的时候指定函数模板的类型
2.类模板
类模板它允许在类中定义一个或者是多个类型参数
示例:
类模板的实例化:
在下面创建类对象的时候,在<>中显示的指定了类对象
T * data:
用于接受T数组的首地址
3.非类型模板参数
非类型模板参数,是允许你将值(而并不是类型)作为参数传给模板
在定义的模板,允许传入的参数接受的类型:
-
整型(
int
,char
,long
等) -
枚举类型(
enum
) -
指针或引用(指向对象、函数或类成员的指针/引用)
-
C++20 起:浮点类型、字面量类类型(如
std::string_view
)等。
代码示例:
4.模板的特化
特化的本质:为模板参数的某个实例提供专属的实现,编译期间,实参选择最优的选择
特化有分为全特化和偏特化
4.1.全特化
类模板和函数模板都支持全特化
全特化的关键规则:
-
特化版本的模板参数列表必须为空(
template <>
)。 - 特化的类 / 函数名必须与原模板相同,参数列表必须精确匹配实参类型。
- 全特化优先级高于通用模板,编译期优先选择。
语法形式:
示例:类模板的全特化
示例2:函数模板的全特化
4.2.偏特化
为模板的部分参数指定类型 / 值,或对参数的特性(如指针、引用、常量性)进行约束。
仅类模板支持偏特化,函数模板不支持
语法形式:
1.参数个数偏特化(减少参数数量)
2.类型特性偏特化(指针、引用、CV 限定符)
5.模板分离编译
核心问题:模板的实例化时机
模板的编译模型:
- 声明阶段:编译器仅检查模板语法,不生成代码。
- 实例化阶段:当模板被具体类型 / 值使用时,编译器才生成对应代码(如
Vector<int>
)。 - 关键:实例化时必须同时可见模板的声明和定义,否则编译器无法生成正确代码。
对比:普通类VS模板类
普通类:
编译器分两步处理:
1.编译 a.cpp
生成 A::f()
的符号。
2.编译 main.cpp
时知道 A::f()
存在,链接时解析符号。
模板类:
编译器行为:
1.编译 vec.cpp
时,模板未被实例化,不生成任何代码。
2.编译 main.cpp
时,需要 Vector<int>::push
的定义,但仅看到声明,无法生成实例化代码。
3.链接时,main.obj
缺少 Vector<int>::push
的符号,报错未定义引用。
解决方法:
1.包含编译:
在类模板中,定义也写在同文件中
2.显示实例化:
在.cpp文件中,对类模板和成员函数进行实例化