模板声明与定义必须同在头文件中,否则链接时报错;函数模板类型推导要求参数类型一致,类模板需显式指定参数或依赖C++17 CTAD;偏特化仅限类模板,函数模板应优先重载而非特化。

template 声明必须在头文件里写
因为编译器需要在实例化时看到完整的模板定义,不能像普通函数那样只放声明。如果你把 template 函数声明放在 .h,定义却放在 .cpp,链接时大概率报 undefined reference 错误。
常见做法是:全部写在头文件中;或者用显式实例化(不推荐新手用)。
- 函数模板、类模板的定义都得和声明一起出现在头文件中
- 如果非要用
.cpp,得在该文件末尾加template void foo这类显式实例化语句(); - 别指望
#include "xxx.cpp"来绕过——这会破坏模块边界,且多个翻译单元包含时可能引发 ODR 违规
函数模板参数类型推导不是万能的
比如你写 template,调用 swap(x, y) 时,T 能推出来;但如果你传入 int 和 long,编译器就懵了——两个参数类型不一致,无法统一推导出一个 T。
- 避免混合类型传参,或改用两个模板参数:
template - 用
auto参数(C++20 概念约束前的简化写法)不如明确写template清晰 - 引用/const 修饰会影响推导结果,
const int&推出的T是int,不是const int
类模板必须显式指定模板参数才能定义对象
像 std::vector 这种,你不能直接写 vector v;,必须写 vector 或用 auto(配合初始化表达式)。
立即学习“C++免费学习笔记(深入)”;
类模板不支持自动推导(C++17 才给构造函数加了类模板参数推导,但仅限于构造函数调用时)。
-
std::pair p{1, 2.0};可以推导成std::pair,但这是靠构造函数模板 + CTAD 实现的 -
MyContainer c;直接报错:缺少模板参数列表 - 别在类模板里嵌套未绑定的
template——语法不允许
模板特化容易写错,优先用 constexpr if(C++17)或概念(C++20)
全特化(如 template struct MyTrait)没问题,但偏特化(template)只允许用于类模板,函数模板不支持偏特化——很多人在这栽跟头。
- 函数模板想“分情况”,用重载比特化更自然、更安全
- C++17 的
if constexpr可以在编译期分支,避免写多组特化 - 模板参数包展开、递归特化这些进阶操作,先确保基础推导和实例化不出错再碰
真正难的不是语法怎么写,而是想清楚哪些逻辑该交给模板参数决定,哪些该留在运行时。泛型不是“把所有类型都塞进去”,而是让类型差异变成可验证、可组合的契约。










