首先你必须了解模板机制。模板不被编译,它们在使用时被实例化,然后它们的实例被编译。因此编译器需要使用模板函数在每个模块中拥有完整的模板定义,以便首先根据您传递的参数实例化它们。
为了解决您的问题,有三种解决方案,但您会发现它们都导致相同的结果。您可以在类定义中的头文件中实现整个模板(我们使用 .hxx 而不是 .h 为它们添加后缀,以准确说明它们包含模板定义):
// Foo.hxx
#ifndef __FOO_HXX__
#define __FOO_HXX__
class Foo {
public:
template <class T>
void bar(const T& t) {
t.doSomething();
}
};
#endif
或者你可以从类中外部化定义,但仍然在头文件中:
// Foo.hxx
#ifndef __FOO_HXX__
#define __FOO_HXX__
class Foo {
public:
template <class T>
void bar(const T&);
};
template <class T>
void Foo::bar(const T& t) {
t.doSomething();
}
#endif
最后,您可以在外部文件中实现模板方法主体(出于相同原因,以 .cxx 为前缀)。它将包含方法的主体,但不包括“Foo.hxx”。相反,它是“Foo.hxx”,它将在类定义之后包含“Foo.cxx”。这样,当编译器解析 #include 指令时,它会在同一个模块中找到整个模板定义,并允许它实例化它:
// Foo.hxx
#ifndef __FOO_HXX__
#define __FOO_HXX__
class Foo {
public:
template <class T>
void bar(const T&);
};
#include "Foo.cxx"
#endif
// Foo.cxx
template <class T>
void Foo::bar(const T& t) {
t.doSomething();
}
这 3 种实现模板的方法之间的选择是一个可读性(和品味)的问题。
第二和第三在生成的代码方面是等效的,但我宁愿不使用 cxx 文件解决方案,因为当您忘记反转包含时,它通常会导致愚蠢的错误。
此外,STL 或 Boost 等知名 C++ 库仅在头文件中提出其代码,这是良好设计的标志。通过在标题中使用外部定义,您可以阐明类的定义。您还可以防止编译器自动内联方法,根据 Herb Sutter http://www.gotw.ca/gotw/033.htm,这有时会导致结果不佳