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

C++ 为什么模板类的实现和声明应该在同一个头文件中?,c++,templates,C++,Templates,为什么模板类的实现和声明应该在同一个头文件中?你们谁能举例说明一下吗?编译器需要访问整个模板定义(而不仅仅是签名),以便为模板的每个实例化生成代码,所以需要将函数的定义移动到标题中 有关更多详细信息,请阅读。类模板的定义及其成员函数的实现必须对使用不同类型实例化它的每个地方都可见。i、 e.为了实例化myTemplate,您需要查看myTemplate的完整定义和实现 最简单的方法是将模板及其成员函数的定义放在同一个标题中,但还有其他方法。例如,您可以将成员函数实现放在单独包含的单独文件中。然后

为什么模板类的实现和声明应该在同一个头文件中?你们谁能举例说明一下吗?

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


有关更多详细信息,请阅读。

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

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

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


i、 e.如果您将
myTemplate
myTemplate
定义为
extern
,则可以很好地使用它们,但是如果
myTemplate
未定义
extern
,则在没有实现的情况下无法使用它们。

对于一个普通类,该声明仅足以进行编译,并将链接相应的定义

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

这一差异在中有更好的解释。

他们不必这样做

必要的是,模板定义在实例化点(使用它的地方)是可见的,这样编译器就可以在此点从模板派生类/函数

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

// 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; };
//foo_fwd.hpp
模板结构Foo;
//福岛水电站
#包括“foo_fwd.hpp”
模板结构Foo{typedef std::pair 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_ {};
//is_foo.hpp
#包括
#包括“foo_fwd.hpp”
样板
结构是foo:boost::mpl::false{};
样板
结构是foo:boost::mpl::true{};

这可以加快编译时间。

它们必须在同一个编译单元中可见。如果两者都包含,则它们可以位于不同的文件中。事实上,将声明和实现拆分为两个文件并不少见。标题通常会包含实现文件。@MSalters:这对于模板类来说是有问题的,这正是这个问题所涉及的。我希望我能否决这些评论。@Tomalak Geret'kal:一点也不。在“Foo.h”中有一个声明,在“Foo.impl”中有定义。标题保护前的最后一行“foo.h”是“#include”foo.impl”。预处理器运行后,不再有任何区别。它们可能位于不同的文件中,但以相同的翻译单元结尾-这对编译器来说才是最重要的。@mAlters:好的,好的。事实上我把你的最后一句话完全倒过来读了。:)不,你不需要。你可以在每个TU中手动编写定义,但当然页眉约定是为了帮助你避免这些废话。:@LightnessRacesinOrbit我可以问一下TU是什么吗?@athos@LightnessRacesinOrb明白了,谢谢!