类模板声明必须写 template<typename T>,漏写会导致编译报错,如“'T' was not declared in this scope”,因编译器需明确其为待填充类型的骨架。

类模板声明时必须写 template<typename T>,漏掉会编译报错
类模板不是普通类,编译器需要明确知道这是个待填充类型的骨架。漏写 template<typename T> 或写成 template<class T>(虽然语法合法但风格不统一)都可能引发后续推导失败。
常见错误现象:error: 'T' was not declared in this scope 或 error: expected unqualified-id before ',基本都是因为声明位置不对或根本没写模板头。
- 模板头必须紧贴在
class关键字前,中间不能有空行或注释隔开 -
typename和class在这里等价,但建议统一用typename,尤其涉及嵌套类型时更安全 - 如果模板参数不止一个,比如
template<typename T, size_t N>,N是非类型参数,不能省略类型说明
实例化类模板不能用 new MyClass 这种写法
模板类不生成实际类型,直到你给出具体实参。写 MyClass 而不带尖括号,编译器根本不知道你在指谁。
使用场景:定义变量、作为函数参数、作为返回类型、在 std::vector 里存对象等,都必须显式指定模板实参。
立即学习“C++免费学习笔记(深入)”;
- 正确写法是
MyClass<int> obj;或auto obj = MyClass<double>{}; -
new MyClass<int>可以,但new MyClass直接报错:error: missing template arguments before ';' token - C++17 后支持类模板参数推导(CTAD),但前提是构造函数能明确推导,比如
MyClass obj{42};能推成MyClass<int>,但别依赖它掩盖设计问题
成员函数定义在类外时,函数模板头和类模板头都要写
很多人只记得给类加 template<typename T>,结果在类外定义成员函数时忘了再写一遍,导致链接失败或隐式实例化失败。
性能影响:定义分离不当会导致多个翻译单元重复实例化,增大目标文件体积;但过度内联又可能破坏封装。
- 类内定义的函数自动成为内联函数,适合简单逻辑(如 getter)
- 类外定义必须双模板头:
template<typename T> template<typename U> void MyClass<T>::func(U u) { ... }(注意第二个template是成员函数自己的模板) - 如果成员函数本身不依赖模板参数,可以不写第二层模板头,但函数签名里仍要体现
T,比如template<typename T> void MyClass<T>::print() const
特化类模板前必须先有主模板声明
直接写 template<> class MyClass<std::string> { ... }; 而不事先声明主模板,GCC 和 Clang 都会报 error: explicit specialization of undeclared template。
兼容性影响:全特化没问题,但偏特化(如 template<typename T> class MyClass<T*>)在某些老版本 MSVC 上支持不稳,建议优先用 SFINAE 或 if constexpr 替代。
- 主模板声明可以是空的:
template<typename T> class MyClass;,之后再定义或特化 - 特化版本里的成员不必和主模板一致,但接口设计要保持语义连贯
- 别把特化当重载用——它替换的是整个类,不是某个函数
最容易被忽略的是:模板代码几乎必须全放在头文件里。实现写在 .cpp 里会导致链接时找不到实例化体,除非你显式强制实例化(template class MyClass<int>;),但这只治标不治本。











