C++类成员函数传递带模板变量结构体的问题及链接错误排查
C++类模板成员函数传递带模板参数的结构体时的编译与链接问题
一、初始编译错误(no matching function for call to)的原因及解决
错误原因
原代码中A::test的模板声明要求两个参数必须是同类型的指针:
template <typename T> void test(T *, T *);
但你传入的ob_1是msg_1<int>*,ob_2是msg_2<int>*——这是两个完全独立的类型(即便它们的模板参数都是int,msg_1和msg_2是不相关的模板结构体),编译器无法匹配到合适的函数实例,因此抛出编译错误。
解决方法
修改test函数的模板,让它接受两个独立的模板参数,分别适配msg_1和msg_2的内部类型:
class A { public: int a; int b; // 用两个模板参数分别对应msg_1和msg_2的模板类型 template <typename T, typename U> void test(msg_1<T> *t1, msg_2<U> *t2); }; template <typename T, typename U> void A::test(msg_1<T> *t1, msg_2<U> *t2) { cout << "Inside test @todo Do something"; }
此时编译器可以根据传入的参数推导出T=int、U=int,生成对应的函数实例,编译即可通过。
二、实际项目中的链接错误(undefined reference)的原因及解决
错误原因
在线编译器能运行但实际项目报错,核心问题是C++模板的定义可见性规则:
- 模板并非可直接编译的代码,只有当编译器看到具体的模板参数(比如
T=msg3、U=msg3)时,才会生成对应的函数实例。 - 如果把
A::test的模板定义放在.cpp文件中,而调用代码(如main所在文件)只包含了A的头文件(仅有模板声明,无定义),编译器在编译调用代码时无法生成test<msg3, msg3>的实例;链接阶段,链接器找不到该实例的二进制代码,就会抛出undefined reference错误。
解决方法
有两种常用修复方式:
将模板成员函数的定义放在头文件中
把A::test的定义直接写在类内部,或在类声明的同一个头文件中紧跟类声明:// A.h class A { public: int a; int b; template <typename T, typename U> void test(msg1<T> *t1, msg2<U> *t2) { cout << "Inside test @todo Do something"; } };所有包含
A.h的文件都能看到完整的模板定义,编译器可在需要时自动生成对应实例。在模板定义所在的.cpp文件中显式实例化所需版本
若必须将模板定义放在.cpp文件中,可在该文件末尾显式实例化项目用到的模板参数组合:// A.cpp template <typename T, typename U> void A::test(msg1<T> *t1, msg2<U> *t2) { cout << "Inside test @todo Do something"; } // 显式实例化项目中需要的特定版本 template void A::test<msg3, msg3>(msg1<msg3>*, msg2<msg3>*);编译器会在编译
A.cpp时生成该实例的代码,链接阶段即可找到对应符号。
内容的提问来源于stack exchange,提问作者Louis
相关产品推荐
相关产品推荐

