C ++模板在.h中声明,在.hpp中定义

时间:2010-08-19 21:14:10

标签: c++ templates header

我看到了一些代码,其中开发人员在.h文件中定义了一个类模板,并在.hpp文件中定义了它的方法。这让我有点意外。

在处理模板时,C ++中是否有特定的约定以及它们应该包含哪些文件?

例如,假设我有一个Vector类模板,其中包含向量运算方法(加,减,点等)。如果模板参数是float(比较运算符),我还想要专门化某些函数。你如何在文件之间分离所有这些(指定是否.h,.hpp,.cpp)。

7 个答案:

答案 0 :(得分:18)

通常(根据我的经验,YMMV)hpp文件是#include - 来自CPP的文件。这样做是为了将代码分解为两个物理文件,一个主要包含和一个实现详细信息文件,您的库的用户不需要知道。它是这样完成的:

super_lib.h(客户需要的唯一文件#include

template<...> class MyGizmo
{
public:
  void my_fancy_function();
};

#include "super_lib_implementation.hpp"

super_lib_implementation.hpp(您的客户端不直接#include这个)

template<...> void MyGizmo<...>::my_fancy_function()
{
 // magic happens
}

答案 1 :(得分:2)

这听起来很不寻常。模板的定义和所有特化必须与其声明一起编译,export模板除外,这是一个实际上不存在的特性。

C ++ 0x确实引入了extern模板声明,它允许您在不同的源文件(翻译单元)中定义显式特化。这已经成为GCC和其他平台的扩展。

分成两个文件可以帮助“隐藏”一点实现,或者允许使用doxygen进行某种懒惰。

啊哈!它也可能通过预编译头改善编译时间。编译器可以基于每个文件缓存头。然后可以修改单独的“实现”标题而不触及“接口”标题。但反之亦然,实现头仍然需要大部分编译时间,并且增益将非常脆弱并且依赖于平台和所做的特定更改。最后,PCH改善了几个源文件的时间,优化头依赖性是毫无意义的。

答案 2 :(得分:2)

在我看来,这是一种分离代码的混乱方式。 .h通常代表 C ++标题标题.hpp。将模板定义放入.hpp,而其他代码放入.h似乎滥用文件扩展名。

模板代码通常都与模板声明一起写在一个标题中,或者在另一个标题中也可以像.tcc或其他东西一样特别添加,然后包含在放置模板声明的标题中。但实际上,只要您在项目中保持一致,文件扩展名就无关紧要了。

例外情况是您使用显式实例化,并确切知道您将需要什么实例化。想象一下,你有一个模板,恰好有两个实例:

template<typename T>
struct SymbolTable {
  T *lookup();
  // ...
};

template struct SymbolTable<GlobalSym>;
template struct SymbolTable<LocalSym>;

您无需将lookup和其他人的定义放入标题中。您可以将它们全部放入.cpp文件中,同时放入两个显式实例化指令。

你问的最后一点是关于一个不同的主题:明确的专业化。我建议你就此提出一个单独的问题。简而言之,所有模板参数都具有具体值/类型的显式特化定义应放入.cpp文件中,但需要将它们的声明放入标题中(告诉其他人这些特定成员是专用的) )。

答案 3 :(得分:1)

我从来没有听说过.h中的类声明和.hpp中的模板定义。我见过的每个项目都采用.h.hpp表示相同的方法,你应该标准化一个(通常是.h)。

模板方法可以放在.h文件的末尾,也可以放在单独的-inl.h文件中(例如Google C++ Style Guide所建议的)。

答案 4 :(得分:1)

我认为分离接口(.h)和实现(.hpp)文件的一个方面是模板的用户(即另一个开发人员)只需要查看.h文件以了解如何使用模板不会被实际实施分散注意力。

答案 5 :(得分:0)

如果我们在.h文件中定义类模板,并在.hpp文件中定义其方法,那么我们必须{。1}} .h文件中的.hpp文件。简单地在.h文件的结束处定义方法(然后不需要.hpp文件)会更容易。

答案 6 :(得分:0)

Boost库对包含声明AND实现的标头使用“.hpp”。在这种情况下,不需要与(预编译的)库链接。

关于Boost的想法,像“.inl”这样的扩展可能是描述模板声明头的“实现”源文件的好主意。