警告:没有 必要 将实现放在头文件中,请参阅本答案末尾的替代解决方案。
无论如何,代码失败的原因是,在实例化模板时,编译器会使用给定的模板参数创建一个新类。例如:
template<typename T>
struct Foo
{
T bar;
void doSomething(T param) {/* do stuff using T */}
};
// somewhere in a .cpp
Foo<int> f;
当读取此行时,编译器将创建一个新类(我们称之为 FooInt
),它相当于以下内容:
struct FooInt
{
int bar;
void doSomething(int param) {/* do stuff using int */}
};
因此,编译器需要访问方法的实现,才能使用模板参数(在本例中为 int
)实例化它们。如果这些实现不在标头中,则无法访问它们,因此编译器将无法实例化模板。
解决此问题的常见方法是将模板声明写在头文件中,然后在实现文件(例如 .tpp)中实现该类,并在头文件的末尾包含该实现文件。
Foo.h
template <typename T>
struct Foo
{
void doSomething(T param);
};
#include "Foo.tpp"
Foo.tpp
template <typename T>
void Foo<T>::doSomething(T param)
{
//implementation
}
这样,实现仍然与声明分离,但编译器可以访问。
替代解决方案
另一个解决方案是保持实现分离,并明确实例化您需要的所有模板实例:
Foo.h
// no implementation
template <typename T> struct Foo { ... };
Foo.cpp
// implementation of Foo's methods
// explicit instantiations
template class Foo<int>;
template class Foo<float>;
// You will only be able to use Foo with int or float
如果我的解释不够清楚,你可以看看关于 这个主题的 C++ 超级常见问题解答 .