库设计混乱.. "public" / "private" (template) headers, 库文件..?

Library design confusion.. "public" / "private" (template) headers, library files..?

我正在尝试编写我的第一个(非常)小的库,目前仅 self-use。在此过程中,我遇到了有关如何以合乎逻辑的方式分隔 headers/source code/object 文件的问题。

更具体地说,我正在编写一个小型模板化容器 class,因此我必须在其 header 中包含此 class 的实现。

我有这样的目录结构:

include/ - "public" .hh header files included by extern projects
src/ - .cc files for implementation (+ "private" .hh header files?)
lib/ - .o compiled library files linked by extern projects

我已经不确定这是否有意义。在我的例子中,我还写了一些 helper-classes 供我的模板化容器 class 使用,其中之一类似于迭代器。所以我有以下文件:

container.hh
container.cc
container_helper.hh
container_helper.cc
container_iterator.cc
container_iterator.hh

虽然我想在外部项目中访问它们的功能(例如递增迭代器),但对我来说,一个项目专门

是没有意义的
#include "container_iterator.hh"

现在,因为我希望项目能够使用容器 class,所以我放置了 "container.hh" 和 "container.cc"(因为它必须包含在 "container.hh" 中,因为模板的)放入 "include/" 目录,然后由其他项目包含。 现在我的困惑出现了.. 容器 class 需要访问助手 classes,但我不希望其他项目只包含助手 classes,所以这似乎是错误的也将助手 classes 放入 "include/" 目录。相反,我会将它们放在 "src/" 中。 但是如果我这样做,那么要将这些包含在 "include/container.cc" 中,我必须使用相对文件路径

#include "../src/container_iterator.hh"

但是现在如果我 "distribute" 我的库到一个外部项目,即我只让 "include/" 目录对编译器可见,它不会编译(?),因为“../src/container_iterator.hh" 不存在。 或者我编译容器 class 并将其作为库放入 "lib/",然后由其他项目链接?但即便如此,我是否仍然需要包含 header "container.hh",才能找到导致同样问题的函数声明?

基本上我在这里迷路了..标准是如何做到这一点的?例如。我可以

#include <vector>

,但我不知道任何 header 只包含 std::vector::iterator,这样做没有任何意义。

在我的阐述中,我一定是在胡说八道,但我找不到哪里。我想我明白 header 和库 is/should 是什么,但是当涉及到如何为实际项目设计 and/or "distribute" 它们时,我被卡住了。即使在我开始学习 C++(或与此相关的任何语言)时,我也一直遇到这样的问题,似乎没有一门课程/没有一本书解释如何实现所有这些概念,只是在它们已经存在时如何使用它们。 =18=]

编辑

为了澄清我的困惑(?)更多..(评论有点太长了)我之前确实读过将模板化 classes 的实现放入 header,其中这就是为什么我意识到我至少需要将 "container.cc" 放入 include/ 目录中。虽然我不是特别喜欢这样,但至少外部用户应该清楚不要包含“.cc”文件。

我是否应该将这也理解为将模板化 classes 编译到库中是没有意义的,因为所有这些都将始终包含在内? (所以模板代码总是 open-source?..这听起来不对?)

在这种情况下,我仍然想知道 STL 是如何做到的,vector 是否在它自己的 header 中声明和定义它的迭代器?或者我可以为 vector::iterator 包含一个单独的 header,这样做没有意义吗?


希望我清楚地解释了我的意图,如果没有,请发表评论。 感谢您的帮助!

根据我的经验,处理问题的最常用方法是 headers 模板声明和文档(您的 .hh 文件),其中还包括 .inc.tcc(您的偏好)带有模板定义的文件。我还建议将外部项目可能包含的所有文件保存在同一个文件夹中,但如果您想保持干净,请将 .inc/.tcc 文件放在 include 中的文件夹中称为 detail(如果您喜欢 GNU 风格,则称为 bits)。 将东西放在详细信息文件夹中, 并且使用一个奇怪的扩展应该足以阻止用户。

回答您的其他问题: 由于 C++ 模板的性质, 您使用的模板部分的全部来源 必须出现在翻译单元中(即 #include'd), 你可以使用explicit instantiation 对于有限数量的参数 (不过,这通常对容器没有用)。 因此,对于大多数用途,您必须分发模板的源代码,但是, 当然,(如评论中所述)"open source" 是关于许可证的, 不是来源可见性。

至于标准库,我们以<vector>为例。 GNU C++ 库有一个 vector 文件,其中(除其他外)包括 bits/stl_vector.h 其中包含声明和文档, 并包含一个具有定义的 bits/vector.tcc。 LLVM 的 libc++ 只有一个巨大的文件, 但将声明放在顶部(没有文档!) 以及底部的所有定义。

最后一点,有很多开源的 C++ 库,您以后可以看看以获取灵感!