c++ - 让细节命名空间代码看不见 - 优雅

标签 c++ idioms forward-declaration

假设我正在编写一个仅包含标题或主要包含标题的库,并且具有以下代码:

using my_type = int;

namespace detail {
    inline void foo() { my_type x; do_foo_stuff(x); }
}

inline void bar() { do_bar_stuff(); detail::foo(); }
inline void baz(my_type y) { do_baz_stuff(y); detail::foo(); }

我要放置foo()在不同的文件中。动机是我有很多这样的详细和不详细的函数,我希望带有我的公共(public) API 的标题不会被 detail 中出现的内容弄乱。 ,并且不适合直接使用。

问题是 - 这样做的惯用方法是什么?
  • 我不能只包含一个带有 detail:: 的文件我的公共(public) header 末尾的代码 - 因为声明需要在使用时进行。
  • 我不能只包含一个带有 detail:: 的文件我的公共(public) header 开头的代码 - 因为它们依赖于一些公共(public)定义,例如类型和常量。让我们假设它们不依赖任何函数。

  • 所以它不能是这两个选项之一。

    最佳答案

    因为通常头文件包含声明,而源文件包含实现,所以人们认为头文件是接口(interface)、公共(public) api,而源文件包含实现细节。在库中,用户(库的消费者)看不到源文件的内容,但可以看到标题,这一事实进一步强化了这一点。

    然而这是错误的:

  • 标题确实包含定义(模板、内联函数和变量),
  • header 包含私有(private)类成员的声明和具有内部链接的符号(静态非本地和匿名命名空间)。这显然不是 API 的一部分。
  • 一个库将公开一个符号(类、函数),即使它仅在内部使用并且不是 API 的一部分(除非它仅在一个 CU 上使用并且具有内部链接)
  • 库 header 会将其使用的所有 header 引入消费者代码,即使库 API 不需要其中一些 header 。这将在用户代码中带来不需要的符号,使命名空间变得困惑。

  • 头文件和源文件的分离不是在公共(public)接口(interface)/实现屏障上完成的。这种代码分离只是 C++ 及其 C 遗产的设计方式的产物。 C++ 不需要多遍编译器,因此它需要在使用前声明和一个定义。所以标题是一个解决方案。它们不是 API 规范。

    所以不幸的结论是 C++ 没有 API/实现分离,尝试使用 header 是不成功的。

    现在回答您的问题:我所知道的惯用方式确实是使用 detailsimpl命名空间。据了解,以这种方式命名的命名空间包含库实现细节,不应在用户代码中使用。我个人不会改变你最初的设计。

    C++20 终于引入了模块,afaik 解决了这个问题。现在,我们将在消费者和公共(public) API 中看不到的内部符号明确区分开来。

    关于c++ - 让细节命名空间代码看不见 - 优雅,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60960693/

    相关文章:

    javascript - WebAssembly 包括 OpenCV

    go - 如何以惯用方式构建现有包的扩展

    c - 范围前向声明

    c++ - 传递指向临时对象的指针

    c++ - 在 Linux 上构建 boost

    C++ 样式 : copyable handle wrapper classes

    generics - 尽可能实现 Into,否则使用 TryInto

    c++ - 派生内部类的前向声明

    c++ - 如何转发声明 C++ 模板类?

    c++ - 根据 C++ 中另一个数组的成员对数组进行排序