使用模板定义类时出现链接编译错误
解决C++模板类分开编译时的未定义符号链接错误
问题场景
现有三个文件:
类定义文件(myClass.h)
#ifndef _myclass_h #define _myclass_h template <typename ValueType> class myClass { public: myClass(); }; #endif
类实现文件(myClass.cpp)
#include "myClass.h" template <typename ValueType> myClass<ValueType>::myClass() { }
测试文件(testMyClass.cpp)
#include "myClass.h" int main() { myClass<int> cls; return 0; }
执行编译命令:
g++ -std=c++11 -o testMyClass myClass.cpp testMyClass.cpp
出现链接错误:
Undefined symbols for architecture arm64: "myClass<int>::myClass()", referenced from: _main in testMyClass-595230.o ld: symbol(s) not found for architecture arm64 clang: error: linker command failed with exit code 1 (use -v to see invocation) make: *** [testMyClass] Error 1
问题原因
C++模板采用按需实例化机制:编译器只有在看到具体的模板实例(比如myClass<int>)时,才会生成对应的模板代码。当把模板实现放在单独的.cpp文件时:
- 编译
myClass.cpp阶段,编译器不知道后续会用到myClass<int>实例,因此不会生成myClass<int>::myClass()的具体代码; - 编译
testMyClass.cpp阶段,编译器仅能看到头文件中的模板声明,没有实现代码,只能生成对该构造函数的引用; - 链接阶段,找不到对应符号就会报错。
解决方案
方案1:将模板实现移到头文件中
这是最通用的做法,可直接把实现写在类定义内部,或在头文件末尾添加类外实现:
#ifndef _myclass_h #define _myclass_h template <typename ValueType> class myClass { public: // 实现直接写在类内 myClass() { } }; // 或者类外实现放在头文件末尾 // template <typename ValueType> // myClass<ValueType>::myClass() { } #endif
包含头文件的testMyClass.cpp能看到完整实现,编译器可正常生成myClass<int>的实例代码。
方案2:在实现文件中显式实例化所需模板类型
如果坚持分开存放代码,可在myClass.cpp末尾显式指定需要实例化的模板类型,告诉编译器提前生成对应代码:
#include "myClass.h" template <typename ValueType> myClass<ValueType>::myClass() { } // 显式实例化int类型的模板类 template class myClass<int>;
缺点是后续新增模板类型(如myClass<double>)时,必须手动添加对应的显式实例化语句。
方案3:用专用模板实现文件(.tpp)拆分代码
这种方式兼顾代码结构清晰和编译需求:
- 创建
myClass.tpp存放模板实现:
#include "myClass.h" template <typename ValueType> myClass<ValueType>::myClass() { }
- 修改
myClass.h,在末尾引入该文件:
#ifndef _myclass_h #define _myclass_h template <typename ValueType> class myClass { public: myClass(); }; // 引入模板实现文件 #include "myClass.tpp" #endif
包含头文件时会自动加载实现代码,效果与方案1一致,但代码结构更清晰。
内容的提问来源于stack exchange,提问作者Dan
相关产品推荐
相关产品推荐

