库设计混乱.. "public"/"private"(模板)标题,库文件..?

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

本文关键字:标题 文件 模板 private 混乱 public      更新时间:2023-10-16

我正在尝试编写我的第一个(非常)小的,目前只有自用的库。在这个过程中,我遇到了关于如何以逻辑方式分离我的头/源代码/对象文件的问题。

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

我有一个这样的目录结构:

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

我已经不确定这是否有意义......就我而言,我还编写了一些由我的模板化容器类使用的帮助程序类,其中一个类似于迭代器。所以我有以下文件:

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

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

#include "container_iterator.hh"

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

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

但是现在如果我将我的库"分发"到外部项目,即我只使编译器对"include/"目录可见,它将不会编译(?),因为"../src/container_iterator.hh" 不存在。 还是编译容器类并将其作为库放入"lib/"中,然后由其他项目链接?但即便如此,我仍然不需要包含标头"container.hh",以便能够找到函数声明,这会导致同样的问题?

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

#include <vector>

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

在我出国的某个时刻,我一定在胡说八道,但我找不到在哪里。我想我理解标题和库是什么/应该是什么,但是当涉及到如何为实际项目设计和/或"分发"它们时,我陷入了困境。即使我开始学习C++(或任何语言),我也不断遇到这样的问题,似乎没有任何课程/书籍解释如何实现所有这些概念,只有当它们已经存在时如何使用它们。

编辑

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

我是否也应该认为这意味着将模板化类编译到库中是没有意义的,因为所有类都将始终包含在内? (所以模板化代码总是开源的?..这听起来不对?

在这种情况下,我仍然想知道 STL 是如何做到的,矢量是否在自己的标头中声明和定义其迭代器?或者我可以包含 vector::itrator 的单独标头,这样做毫无意义?


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

根据我的经验,处理问题的最常见方法是使用带有模板声明和文档(.hh文件)的标头,其中还包括带有模板定义的.inc.tcc(您的首选项)文件。我还建议将外部项目可能包含的所有文件保留在同一文件夹中,但是如果您想保持干净,请将.inc/.tcc文件放在名为detail的文件夹中include(如果您喜欢GNU样式,则bits)。 将内容放入详细信息文件夹中, 使用奇怪的扩展应该足以阻止用户。

要回答您的其他问题: 由于C++模板的性质, 您使用的模板各部分的整个来源 必须存在于翻译单元中(即。#include'd),或者您可以使用显式实例化 对于有限数量的参数 (不过,这对于容器通常没有用)。 因此,在大多数情况下,您必须分发模板的源代码, 当然,(如评论中所述)"开源"是关于许可证的, 不是源可见性。

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

最后,有很多开源C++库,您可以在将来查看以获取灵感!