类模板用template声明,参数名仅为占位符且须被使用;成员函数定义需重复模板头并加作用域解析符;必须在头文件中定义以支持实例化,依赖模板参数的返回类型不可省略typename。

类模板的基本定义语法
类模板用 template 关键字声明,紧跟一个尖括号包裹的模板参数列表,再写 class 或 struct 定义。最简形式就是:template
注意:参数名(如 T)只是占位符,不参与编译,但必须在类体内被实际使用,否则编译器可能报 unused template parameter 警告(某些严格模式下)。
-
typename和class在模板参数中完全等价,都表示类型形参;习惯上对单个类型用typename,对需要继承约束的场景才显式用class - 可以有多个参数:
template,支持默认类型、非类型参数(如size_t)、模板模板参数 - 类内所有成员函数若含模板逻辑,也必须在定义处(或声明处)带上完整模板头,不能只在实现文件里补写
成员函数定义的位置和写法
类模板的成员函数不能像普通类那样在 .cpp 里单独定义——因为编译器需要看到完整定义才能实例化。所以要么全写在头文件里(常见),要么在头文件末尾显式 include 实现文件(如 myclass.tpp)。
成员函数定义时,必须重复模板头,并用作用域解析符标明所属类:template
- 如果函数本身也是模板(比如带额外参数的成员函数),要写两层
template头:templatetemplate void MyClass ::do_something(U x) { ... } - 构造函数、析构函数、
operator=等特殊成员,只要涉及模板参数,同样要带模板头定义 - 返回类型若依赖模板参数(如
T&),不能省略typename前缀,但在成员函数内部一般不需要
显式实例化与隐式推导的区别
类模板不会自动生成代码,只有当被真正使用(如定义变量、取地址、调用成员)时,编译器才按需实例化。例如 MyClass 触发 int 版本生成;而 MyClass<:string> 是另一个独立副本。
- 不写具体类型就直接用类名(如
MyClass)是非法的,会报错use of class template requires template argument list - 不能靠函数参数自动推导类模板实参(C++17 起仅支持类模板实参推导(CTAD),但要求构造函数参数能唯一确定模板参数,且需有对应推导指南)
- 显式实例化声明(
extern template class MyClass)可避免多文件重复实例化,但需确保至少一处有定义;
常见编译错误和排查点
类模板出错往往报错位置飘忽、信息冗长,核心问题通常集中在三处:参数未被使用、定义分离导致链接失败、特化与泛化冲突。
-
error: 'T' was not declared in this scope:常因忘记在成员函数定义前加模板头,或在类外定义时漏写了MyClass作用域:: -
undefined reference to MyClass:典型头/实现分离错误,检查是否把成员函数定义放在了 .cpp 里且没显式实例化::xxx - 部分特化后忘了把泛化版本写全(比如泛化版接受
template,而特化写成template),会导致匹配失败 - 非类型参数如果是浮点数或类类型(C++20 前),会直接编译失败,必须用整型、指针、引用或枚举
类模板的难点不在语法,而在实例化时机和符号可见性——它不像普通类那样“先声明后定义”就能跑通,每一步都要让编译器在需要时能看见完整的模板定义。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











