为什么C++模板只能在头文件中实现
答案:模板的实现并非必须在头文件中。
bug再现:当我尝试将模板的定义和实现分别保存在头文件(Foo.h
)和实现文件(Foo.cpp
)中时,程序在链接时报错:
错误 LNK2019 无法解析的外部符号 "public: void __cdecl Foo<int>::doSomething(int)" (?doSomething@?$Foo@H@@QEAAXH@Z),函数 main 中引用了该符号
以下是头文件和实现文件内容:
Foo.h
template <typename T>
struct Foo
{
void doSomething(T param);
}
Foo.cpp
template <typename T>
void Foo<T>::doSomething(T param){
}
以上代码出错的原因在于,当实例化一个模板时,编译器会根据给定的模板参数创建一个新类,对于上述代码,我们在main.cpp
中对Foo
进行实例化:
//main.cpp
int main(){
Foo<int>f;
}
当读取到 Foo<int>f;
这一行时,编译器将会创建一个新类(我们将其称为 FooInt
),如下所示:
struct FooInt
{
void doSomething(int param);
}
因此,编译器需要访问方法的实现,用模板参数(本例中是int)来实例化他们。如果这些实现没有在头文件中,它们将不可访问,导致编译器无法实例化模板。
通用的解决方法是在头文件中写模板的声明,然后实现类在实现文件中(.cpp
),同时在头文件尾部将实现文件include进来。
Foo.h
template <typename T>
struct Foo
{
void doSomething(T param);
}
#include "Foo.cpp"
Foo.cpp
template <typename T>
void Foo<T>::doSomething(T param){
}
这个时候我们会遇到一个编译错误:错误 C2995 “void Foo<T>::doSomething(T)”: 函数模板已经定义
主要原因是在Foo.h
头文件中包含了Foo.cpp
执行文件,对成员函数进行了定义;而Foo.cpp
执行文件又包含在项目中,再次对成员函数进行了定义,所以会有“函数模板已经定义”的错误信息。可以将模板类对应的Foo.cpp
执行文件从项目中移除,注意是“移除”而不是“删除”。
这样的话,实现依然与声明分离,但是编译器可以正常访问它。
标签:头文件,doSomething,void,C++,cpp,Foo,模板 From: https://blog.csdn.net/ChuJian_cao/article/details/140663370