Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ C++;模板在.h中声明,在.hpp中定义_C++_Templates_Header - Fatal编程技术网

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

C++ C++;模板在.h中声明,在.hpp中定义,c++,templates,header,C++,Templates,Header,我看到一些代码,其中开发人员在.h文件中定义了一个类模板,并在.hpp文件中定义了它的方法。这让我有点吃惊 在处理模板和应该使用什么文件时C++中有特殊约定吗? 例如,假设我有一个Vector类模板,其中包含用于向量运算(加法、减法、点等)的方法。如果模板参数是float(比较运算符),我还想专门化某些函数。如何在文件之间区分所有这些内容(指定是否为.h、.hpp、.cpp)。我从未听说过将类声明放在.h中,将模板定义放在.hpp中。我所看到的每个项目都采用了.h和.hpp意思相同的方法,您应该

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

<>在处理模板和应该使用什么文件时C++中有特殊约定吗?
例如,假设我有一个
Vector
类模板,其中包含用于向量运算(加法、减法、点等)的方法。如果模板参数是
float
(比较运算符),我还想专门化某些函数。如何在文件之间区分所有这些内容(指定是否为.h、.hpp、.cpp)。

我从未听说过将类声明放在
.h
中,将模板定义放在
.hpp
中。我所看到的每个项目都采用了
.h
.hpp
意思相同的方法,您应该在一个项目上进行标准化(通常是
.h


模板方法可以放在
.h
文件的末尾,也可以放在单独的
-inl.h
文件中(例如,根据建议)。

如果我们在.h文件中定义类模板,并在.hpp文件中定义其方法,那么我们必须将.hpp文件包含在.h文件中。只需在.h文件的末尾定义方法(然后不需要.hpp文件)就更容易了。

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

这对我来说很不寻常。模板的定义和所有专门化都必须与其声明一起编译,但
导出
模板除外,该功能实际上并不存在

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

拆分成两个文件可能有助于稍微“隐藏”实现,或者允许doxygen的某种惰性

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

通常(以我的经验,YMMV)一个
hpp
文件是一个
#include
-ed CPP文件。这样做是为了将代码分成两个物理文件,一个是主include文件,另一个是实现细节文件,库的用户不需要知道这些文件。是这样做的:

super_lib.h(您的客户端需要包含的唯一文件)
在我看来,这是一种令人困惑的代码分离方法<代码> h:/>代码代表C++的标题和代码>。将模板定义放入
.hpp
,而将其他代码放入
.h
似乎滥用了文件扩展名

模板代码通常与模板声明一起写在一个标题中,或者写在另一个标题中,该标题也可能带有特殊后缀,如
.tcc
或其他内容,然后包含在放入模板声明的标题中。但实际上,只要在项目中保持一致,文件扩展名并不重要

例外情况是当您使用显式实例化,并且确切地知道您将需要什么样的实例化时。假设您有一个模板,它有两个实例:

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

template struct SymbolTable<GlobalSym>;
template struct SymbolTable<LocalSym>;
模板
结构符号化{
T*lookup();
// ...
};
模板结构SymbolTable;
模板结构SymbolTable;
您不需要将
lookup
和其他内容的定义放入标题中。您可以将它们连同两个显式实例化指令一起放入
.cpp
文件中

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

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


对于Boost idea,扩展名“.inl”可以用来描述模板声明头的“实现”源文件。

将接口和实现分离是个好主意,但可以通过将接口放在顶部在一个文件中完成。不同意“愚蠢”。如果模板库很复杂或有许多函数,从可读性的角度来看,在hpp文件中拆分实现非常有意义。@John:Fine,“不同寻常”。但是,在中间拆分文件并加入<代码> >包括< /代码>,你能获得多少可读性?可读性来自于将原型声明放在顶部,而不是拆分文件。有时很多。我同意通过将实现推到同一个文件的末尾也可以实现这一点,但我个人更倾向于在可能的情况下只将用户需要知道的内容放在头文件中。添加更多内容会让人困惑。不过,我认为这里没有正确或错误的观点。它们也可以放在
.hpp
文件中。事实上
template<...> void MyGizmo<...>::my_fancy_function()
{
 // magic happens
}
template<typename T>
struct SymbolTable {
  T *lookup();
  // ...
};

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