模板类声明必须以template开头,否则编译器不识别为模板;声明与定义须同在头文件中,成员函数定义需重复该前缀并用stack::限定作用域。

模板类声明必须用 template<typename t></typename> 开头
不加这行,编译器根本不会把它当模板——哪怕类里所有成员都用了 T。常见错误是只在实现文件里写 template<typename t></typename>,而头文件中类定义前漏掉,导致链接时报 undefined reference。
标准写法是:声明和定义通常都放在头文件里,且类定义前必须有 template<typename t></typename>;如果非要分离声明/定义(比如为了隐藏实现),定义处也得重复写一遍 template<typename t></typename>,否则编译不过。
注意: typename 和 class 在这里等价,但推荐用 typename,尤其当模板参数可能代表嵌套类型(如 T::value_type)时,typename 更准确。
成员函数定义必须显式带上模板参数列表
即使函数看起来“只是普通函数”,只要它属于模板类,定义时就得带 template<typename t></typename>,而且类名后要加 <t></t>。
例如:
template<typename t>
class Stack {
public:
void push(const T& x);
};
<p>template<typename t>
void Stack<t>::push(const T& x) { // ← 这里不能省略 Stack<t>::,也不能漏 template<typename t>
// ...
}</typename></t></t></typename></p></typename>
容易踩的坑:
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
- 忘记在作用域解析符前写
Stack<t>::</t>,编译器会认为这是全局函数 - 把
Stack<t>::push</t>写成Stack::push,报错non-template class - 模板参数名不一致(比如声明用
T,定义用U),类型系统直接断连
特化模板类要完整重写类体,不能只改部分函数
全特化(如针对 int)不是“重载某个函数”,而是提供一个全新的、非模板的类版本。编译器看到 Stack<int></int> 时,会优先匹配特化版本,完全忽略通用模板。
写法示例:
template
class Stack<int> {
public:
void push(int x) { /* 专用实现 */ }
int pop() { /* 不返回 T&,直接返回 int */ }
};</int>
关键点:
- 特化声明必须以
template开头,后面紧跟类名+具体类型Stack<int></int> - 不能只特化单个成员函数——C++ 不允许偏特化函数,只能偏特化整个类(或全特化)
- 偏特化(如
template<typename t> class Stack<t></t></typename>)只支持类模板,不支持函数模板
模板类实例化发生在使用点,编译器按需生成代码
你写了 Stack<double></double> 和 Stack<:string></:string>,编译器就生成两套独立的二进制代码——不是运行时多态,没有虚表开销,但也意味着每种类型都会膨胀一份实现。
这意味着:
- 没被调用的成员函数不会实例化,哪怕它语法错误(比如对
T调用了不存在的.size()),只要没用到就不报错 - 依赖的类型必须满足函数内实际操作的要求:比如
operator==被调用,那T就得提供它 - 头文件里所有模板代码都得可见,否则其他翻译单元无法实例化——这也是为什么模板几乎都写在头文件里
真正麻烦的往往不是怎么写,而是搞清哪一行触发了实例化、以及 T 到底需要什么接口。报错信息里出现一长串嵌套的 Stack<...>::push</...> 调用栈,基本就是在告诉你:某处用了不满足约束的类型。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










