类模板必须以template声明,不能省略;定义时需显式指定类型参数(如stack),不可自动推导;成员函数若在类外定义,须重复template声明并加作用域限定;定义通常需全部置于头文件中。

类模板不能省略 template 声明,且必须显式指定类型参数,否则编译器根本不会识别为模板。
类模板定义必须带 template<typename t></typename> 前缀
类模板不是普通类,它本身不生成任何代码。你写 class Stack 是无效的;必须写成 template<typename t> class Stack</typename>。这里的 T 是占位符,可以替换成任意类型(如 int、std::string),但名字只是约定,用 U、ValueType 也完全合法。
-
typename和class在此处等价,但推荐用typename,尤其当涉及嵌套类型(如T::value_type)时,typename能明确告诉编译器这是类型名 - 模板参数可以有多个:
template<typename key typename value></typename> - 支持默认参数:
template<typename t typename alloc="std::allocator<T">></typename>
成员函数定义位置决定是否需要重复声明 template
如果所有成员函数都写在类内部(内联定义),只需在类声明前加一次 template<typename t></typename>。一旦把函数体挪到类外,就必须在函数定义前再次写 template<typename t></typename>,并且要带上作用域:Stack<t>::push</t>。
- 错误写法:
void Stack::push(const T& x) { ... }—— 缺少模板头和作用域 - 正确写法:
template<typename t> void Stack<t>::push(const T& x) { ... }</t></typename> - 类内定义自动获得模板上下文,无需额外声明
实例化必须显式写出具体类型,不能靠推导
函数模板能靠参数自动推导 T,但类模板不行。你不能写 Stack s;,必须写 Stack<int> s;</int> 或 Stack<:string> s;</:string>。
- 哪怕构造函数参数足以判断类型,编译器也不会尝试推导(C++17 引入了类模板实参推导(CTAD),但需额外定义推导指引,不是默认行为)
- 使用别名可简化:
using IntStack = Stack<int>; IntStack s;</int> - STL 容器如
std::vector<double></double>就是典型实例化结果,std::vector本身只是模板名
最容易被忽略的是:类模板的定义(包括所有成员函数实现)通常必须全部放在头文件里。因为编译器要在每个用到它的翻译单元中按需生成具体类型的代码,分离 .h/.cpp 会导致链接失败——除非你显式实例化所有要用的类型组合,但这违背泛型初衷。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











