模板声明与定义必须同在头文件(如.hpp),类外成员函数需重复template声明,构造函数推导受限于类型一致性,sizeof/new操作在模板中易引发未定义行为。

template 声明必须和定义写在一起
模板类不是普通类,编译器需要在实例化时看到完整的定义,否则链接会失败——常见错误是把 template<typename t> class Vec;</typename> 声明放在头文件,而把实现塞进 .cpp 文件,结果出现大量 undefined reference to Vec<int>::xxx</int>。
实操建议:
- 所有模板类的声明和定义都放在同一个
.h或.hpp文件里(推荐.hpp) - 如果非要分离,可用显式实例化:在
.cpp末尾加template class Vec<int>;</int>,但只对已知类型有效,无法泛用 - 别依赖前置声明来“加速编译”——对模板无效,反而埋坑
成员函数必须也带 template 参数
很多人写完 template<typename t> class Container</typename>,接着在类内写 void push(T val) 就以为完事了。其实这是错的:类模板的成员函数本身也是模板函数,只是参数被继承了;但一旦你把它定义在类外,就必须重新声明 template<typename t></typename>。
常见错误现象:
立即学习“C++免费学习笔记(深入)”;
- 类外定义
void Container::push(T)报错:未声明的标识符T - 漏写外部定义的
template<typename t></typename>,导致编译器认为你在写非模板函数
正确写法示例:
template<typename T>
class Stack {
public:
void push(const T& x);
};
template<typename T> // ← 这行不能少
void Stack<T>::push(const T& x) {
// ...
}
模板参数推导不适用于构造函数调用
你写了 template<typename t> class Pair { Pair(T a, T b); }</typename>,然后想直接写 Pair p(1, 2.5);?不行。C++17 之前根本不支持类模板参数推导(CTAD),C++17 起虽支持,但仅限于构造函数参数能**唯一确定所有模板参数**的情况。
使用场景与限制:
-
Pair<int> p(1, 2);</int>没问题;Pair p(1, 2);在 C++17+ 可行(推导为Pair<int></int>) -
Pair p(1, 2.5);会失败:两个参数类型不同,无法统一推导出一个T - 若构造函数有默认模板参数或重载,推导更易歧义——这时候老老实实写
Pair<double></double>
别在模板里随便用 sizeof(T) 或 new T[10]
模板代码会在每个实例化点生成一份副本,如果里面用了可能引发未定义行为的操作,问题会被放大。比如 T 是抽象类、未定义析构函数的类型、或含非平凡移动语义的对象,new T[n] 和 sizeof(T) 都可能出事。
容易踩的坑:
-
sizeof(T)对空类返回 1,但某些 ABI 下可能影响内存布局判断——别拿它做偏移计算 -
new T[n]不会调用T的默认构造函数(C++20 前),导致 POD 类型未初始化,非 POD 类型可能跳过构造逻辑 - 优先用
std::vector<t></t>或std::array<t n></t>替代裸 new + sizeof 手动管理
复杂点在于:这些错误往往不报编译错误,运行时才崩,而且只在特定 T 实例下触发——所以测试时别只用 int 和 std::string 跑一遍就完事。










