Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/loops/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++ 我应该何时考虑只制作库头? 显然,模板库只需要是头文件,但是对于非模板,什么时候应该只做页眉?< /p>_C++_Header Only - Fatal编程技术网

C++ 我应该何时考虑只制作库头? 显然,模板库只需要是头文件,但是对于非模板,什么时候应该只做页眉?< /p>

C++ 我应该何时考虑只制作库头? 显然,模板库只需要是头文件,但是对于非模板,什么时候应该只做页眉?< /p>,c++,header-only,C++,Header Only,如果你认为你的非模板库只能是头文件,那么无论如何考虑把它分成两个文件,然后提供一个包含第三个文件,包括 .h >代码>和 .CPP < /代码>(包括一个包含保护) 然后,在许多不同的TU中使用您的库,并且怀疑这可能会花费大量编译时间的任何人都可以轻松地进行更改以测试它 一旦您知道用户可以选择使用该库的方式,答案可能会变成“尽可能随时提供该选项”。几乎任何时候,从多个TU包含它都不会违反ODR。例如,如果您的非静态自由函数引用的是静态全局函数,那么您就倒霉了,因为不同TU中该函数的不同定义将以相

如果你认为你的非模板库只能是头文件,那么无论如何考虑把它分成两个文件,然后提供一个包含第三个文件,包括<代码> .h >代码>和<代码> .CPP < /代码>(包括一个包含保护)

然后,在许多不同的TU中使用您的库,并且怀疑这可能会花费大量编译时间的任何人都可以轻松地进行更改以测试它


一旦您知道用户可以选择使用该库的方式,答案可能会变成“尽可能随时提供该选项”。几乎任何时候,从多个TU包含它都不会违反ODR。例如,如果您的非静态自由函数引用的是静态全局函数,那么您就倒霉了,因为不同TU中该函数的不同定义将以相同的名称引用不同的对象,这是一种ODR冲突。

如果没有模板,则标题中会有实际的定义。这意味着,如果两个文件包含您的头,您将得到多个定义,代码将无法编译

换句话说,将定义放在标题中是一个非常糟糕的主意。您应该只使用声明和模板

至于模板,编译器知道您可能多次包含相同的头,它们不会一次又一次地生成相同的代码


编辑:如果你的意思是“保持一切内联”,我认为这是一个非常糟糕的方法。头文件变得完全不可读,实现中的任何更改都会迫使库中的任何用户重新编译所有内容。

模板库不需要仅为头文件:实现可能包含一些独立于模板参数的片段,并且出于某些原因(例如,代码大小较小)分离成一个特殊的二进制


我无法想象一个非模板库必须只包含头的情况。然而,有时允许所有代码内联可能是合理的性能明智之举。例如,围绕平台特定接口的包装器库,例如同步原语、线程本地存储、特定于平台和编译器的原子操作实现等。您可以遵循Boost.Asio的指导

它们只提供了两个版本的库:header only和header+library

在包含标题之前,它们只需定义(或不定义)一个宏。我认为默认(如果没有定义的话)是只使用头版本


请注意,它们是如何整洁地提供一个要编译的源文件的,该文件定义了所有内容或链接到动态加载库的选项。

当您不介意公开您的IP时。@Nim:它是Boost软件许可证下的开源程序,所以我当然不介意。:)@比利:哦,你进了Boost?格拉茨P@Xeo:没有,但是任何人都可以使用BSL,对吗?(Boost不想要我正在研究的东西;Boost只用于一般用途的库,我正在做的是非常特定于领域的)@Billy:噢,我不知道,对不起。:)哦。从来没有想过这样做+1当
.cpp
#include
d时,如何将函数声明正确设置为
inline
。@Billy:在第三个文件(second.h)中设置一个
#define
,在.cpp中设置一个
#ifdef#定义dou inline#否则#定义dou inline#endif
?我想如果它们被声明为
inline
,那么定义就必须存在于翻译单元的某个地方。@Billy,@DeadMG:对不起,Billy是对的,我写评论时的想法与DeadMG完全相同,但它当然只适用于只有标题的情况。你确实需要一个“正确链接”宏。@Billy,@DeadMG:。。。和IIRC,如果您在header-only的情况下使用_-RIGHT _-LINKAGE _-DAMMIT
static inline
,那么您可以安全地组合以不同方式使用库的TU,但您可能无法在函数中正确使用局部静态变量。如果它只是内联的,那么它们与非内联版本不兼容,所以它必须是一个可执行的范围内的决定使用哪一个。我已经有一段时间没有把这件事搞砸了,这里面有一些复杂因素。您可以将定义放在标题中,只要它们具有内部链接。(例如,它们被声明为
内联的
)有时候,需要为每次更改重新编译并不是一个限制。@Dennis:True。但有时,最好能够提供一个新的共享对象来修复安全问题,而不是强迫您重新编译整个/usr/bin。如果glibc中存在可利用的问题,您可以简单地对其进行更新。如果STL中存在可利用的漏洞,则必须重新编译使用它的所有内容。如果您运行的是Gentoo,这不是问题,但我没有。Alexey:给我看一个STL库,它不仅仅是头文件。对于STL,我指的是容器/算法/迭代器部分,而不是整个标准库。也许,但模板库的模板部分必须仅为标题。翻译单元中需要存在模板定义,以便编译器可以实例化它。有些STL有二进制部分,主要是因为它们都是作为一个普通C++运行时的一部分,它们包含非模板块(例如 LBSTDCXX),或者B包含非模板的组件。至于性能方面,现在大多数编译器都有链接时代码生成,这在很大程度上消除了两个版本之间的性能差异。@Xeo:好的,你可能是对的,STL与语言支持库不同。通常会对标准库和STL有一些混淆。根据STL(标准模板库)的原始定义,STL是一个