警告:这是没有必要把落实在头文件中,看到这个答案的末尾替代解决方案。
无论如何,你的代码失败的原因是,在实例化模板时,编译器会使用给定的模板参数创建一个新类。例如:
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 */}
}
因此,编译器需要访问方法的实现,以使用template参数实例化它们(在这种情况下为int
)。如果这些实现不在头文件中,则将无法访问它们,因此编译器将无法实例化模板。
一种常见的解决方案是将模板声明写入头文件中,然后在实现文件中实现该类(例如.tpp),并在头末尾包含该实现文件。
oo
template <typename T>
struct Foo
{
void doSomething(T param);
};
#include "Foo.tpp"
Foo.tpp
template <typename T>
void Foo<T>::doSomething(T param)
{
//implementation
}
这样,实现仍与声明分开,但编译器可以访问。
另一个解决方案是使实现分离,并显式实例化你需要的所有模板实例:
oo
// 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 ++超级常见问题解答。
实际上,显式实例化必须在.cpp文件中,该文件可以访问Foo的所有成员函数的定义,而不是标头。
“编译器需要访问方法的实现,并使用模板参数(在本例中为int)将其实例化。如果这些实现不在头文件中,则将无法访问它们。”但是为什么在.cpp文件无法由编译器访问?编译器还可以访问.cpp信息,否则它将如何将其转换为.obj文件?编辑:这个问题的答案在这个答案中提供的链接中...
我不认为这可以清楚地解释这个问题,关键显然与编译UNIT有关,本文中未提及
@Gabson:结构和类是等效的,不同的是,类的默认访问修饰符是“私有”,而结构的公共访问修饰符是公共的。通过查看此问题,您还可以了解其他一些细微差异。
我在此答案的开头添加了一个句子,以澄清该问题是基于错误的前提。如果有人问“为什么X为真?” 当实际上X不正确时,我们应该迅速拒绝该假设。