为什么模板类的实现和声明应该在同一个头文件中?

时间:2010-09-20 06:30:01

标签: c++ templates

为什么模板类的实现和声明应该在同一个头文件中?您是否可以通过示例解释它?

4 个答案:

答案 0 :(得分:25)

编译器需要访问整个模板定义(而不仅仅是签名)才能为模板的每个实例化生成代码,因此您需要将函数的定义移动到标题中。

有关详细信息,请参阅The Inclusion Model

答案 1 :(得分:6)

类模板的定义及其成员函数的实现必须对于使用不同类型实例化它的每个地方都是可见的。即,为了实例化myTemplate<int>,您需要查看myTemplate的完整定义和实现。

最简单的方法是将模板及其成员函数的定义放在同一个标​​题中,但还有其他方法。例如,您可以将成员函数实现放在单独包含的单独文件中。然后,您可以从第一个标头中包含它,或者只包含您需要它的实现文件。

例如,一种做法是在一个.cpp文件中为不同的参数集显式实例化模板,并在标头中声明这些实例extern。这样,这些实例化可以在其他源文件中使用,而不需要实现模板成员函数。但是,除非您包含实现文件,否则您将无法使用其他模板参数集。

即。如果您将myTemplate<int>myTemplate<std::string>定义为extern,那么您可以正常使用它们,但如果myTemplate<double>未定义extern那么您不能使用它实施

答案 2 :(得分:4)

对于普通类,声明就足以进行编译,相应的定义将链接

对于模板,编译器还需要定义生成代码。

C++ FAQ中更好地解释了差异。

答案 3 :(得分:4)

他们不必。

模板定义在实例化时(使用它的位置)是可见的,这样编译器就可以在此时从模板中派生类/函数。

但是,对模板类使用两个头文件是非常常见的:

// foo_fwd.hpp
template <typename T, typename U> struct Foo;

// foo.hpp
#include "foo_fwd.hpp"

template <typename T, typename U> struct Foo { typedef std::pair<T,U> type; };

这允许那些不需要完整模板定义的人包含更轻的标题,例如:

//is_foo.hpp
#include <boost/mpl/bool.hpp>
#include "foo_fwd.hpp"

template <typename Z>
struct is_foo: boost::mpl::false_ {};

template <typename T, typename U>
struct is_foo< Foo<T,U> >: boost::mpl::true_ {};

可以加快编译时间。