模板类在定义时类型即参与编译,T是待推导的编译期实体;声明与定义必须同在头文件中,否则链接失败;成员函数定义需双重template前缀;偏特化需谨慎处理const/引用折叠,且不支持函数模板;推导失败常见于隐式转换、右值引用和初始化列表场景。

模板类不是“先写类再套模板”,而是从定义那一刻起,类型就参与编译——T 不是占位符,是待推导的编译期实体。
模板类定义必须写在头文件里
因为编译器需要在每个使用它的翻译单元中实例化具体类型。如果把 template 声明放在 .h,而定义(实现)放在 .cpp,链接时会报 undefined reference to MyClass。
- 所有模板声明和定义都放在
myclass.h中 - 不支持分离式编译(除非显式实例化,但极少用)
- 头文件中避免 #include 过多,否则编译时间飙升
成员函数必须也带 template 前缀
类外定义成员函数时,不能只写 MyClass,必须补全两层 template:
templatetemplate void MyClass ::process(const U& u) { // ... }
第一行针对类模板参数 T,第二行针对成员函数自己的模板参数 U。漏掉任一层都会导致编译失败,错误信息常为 ‘process’ is not a member of ‘MyClass。
立即学习“C++免费学习笔记(深入)”;
偏特化要小心 const 和引用折叠
比如你想对指针类型做偏特化:
特色介绍: 1、ASP+XML+XSLT开发,代码、界面、样式全分离,可快速开发 2、支持语言包,支持多模板,ASP文件中无任何HTML or 中文 3、无限级分类,无限级菜单,自由排序 4、自定义版头(用于不规则页面) 5、自动查找无用的上传文件与空目录,并有回收站,可删除、还原、永久删除 6、增强的Cache管理,可单独管理单个Cache 7、以内存和XML做为Cache,兼顾性能与消耗 8、
templateclass MyContainer { ... };
这能匹配 int*,但匹配不了 const int* 或 int* const——它们是不同类型。更安全的方式是用类型特征配合 std::remove_pointer_t 在主模板内部分支处理,而不是盲目偏特化。
- 偏特化不支持函数模板(只能全特化)
-
MyContainer和MyContainer是独立偏特化,不会自动覆盖 - 若主模板有默认参数,偏特化里不能重复写,默认参数不继承
模板参数推导失败的常见原因
构造函数调用时,编译器不一定能从实参推出 T,尤其涉及隐式转换或右值引用时:
- 传入字面量
42,推导为int;但传入42.0,可能推导为double而非你期望的float - 使用
std::forward时,若模板参数是T&&,传入左值会推导成T&(引用折叠),不是T - 初始化列表构造:
MyClass{1, 2, 3}无法推导T,必须写成MyClass{1, 2, 3}
这时候可以加一个非模板的辅助函数,比如 make_myclass(1, 2, 3),内部用 decltype 或 std::decay_t 控制推导行为。
模板类真正的复杂点不在语法,而在类型依赖路径是否被编译器全程看见——少一个 typename、漏一次 template 关键字、或者在依赖上下文中用了未声明的嵌套类型,错误信息就会跳转到八百行外,而且满屏都是 expected ‘;’ before ‘...’。









