6

在打包代码中使用命名空间的最佳/最干净的方法是什么?

例如,在像boost这样的库中,似乎有非常有条理的命名空间管理,使用了一些技术来消除名称的歧义。然而,重要的是,人们不会看到太多类似的代码

typedef namespace1::namespace2::sth_else::a_class<namespace3::namespace4::b_class> type;

通常,没有太多的跨命名空间,这表明良好的体系结构以及良好的命名空间管理。问题是:什么是好的命名空间管理?

假设我们有这样的文件结构:

component1/...  (depends on reusable_if)
component2/...  (depends directly on reusable_if and on component 1)
reusable/
reusable/some_part/
reusable/some_part/...
reusable/some_other_part/
reusable/some_other_part/...
reusable/SthThatUsesBothReusableParts.h   (implements reusable_if/ISth.h)
reusable/SthThatUsesBothReusableParts.cpp (implements reusable_if/ISth.h)
reusable_if/
reusable_if/ISth.h   (pure abstract class)
reusable_if/ISthElse.h (pure abstract class)
main.cpp (e.g. instantiates SthThatUsesBothReusableParts and passes to component1/2)

之所以有 reusable_if/ 文件夹是因为 component1 和 component2 都想重用相同的接口(因此它们都没有“独占”这些接口)。此外,假设项目确实非常大,并且每个文件夹中的类都需要适当的命名空间。

您将如何在这样的项目中应用命名空间?假设我在 namespace 中声明所有类 reusable/ ::reusable。我应该将 reusable_if 中的接口放入命名空间::reusable还是放入::reusable_if?或者可能没有,因为它被组件1和组件2使用?

component1 和 component2 中的命名空间呢?有什么要记住的吗?关键字using呢?假设我决定添加这个::reusable_if命名空间。我可以将using reusable_if头文件放入组件 1 和组件 2 中,前提using ...是放在命名空间::component1::component2?

我愿意接受任何建议,也包括与上述示例不一定相关的建议。

4

2 回答 2

6

Personal opinion disclaimer. Your question basically asks for subjective answers, and will probably be closed for it, but I'll give it a shot.


Namespaces are primarily useful to avoid identifier clashes. There is "your" namespace (mylib::), and the namespaces of everybody else (std::, boost::, icu::, ...), and that is about as far as namespaces should be taken.

There is little benefit to be had by subdividing your project (as in, "your team's project") into sub-namespaces, unless you get a problem with identifier clashes -- in which case you should reconsider your strategy of calling your classes X and Y. ;-)

Things are a bit different in huge libs, like Boost. They effectively consist of many different projects, maintained by seperate teams, so there's a problem of project-specific identifiers clashing with each other if they were all lumped into boost:: (and the clash possibly not showing up in casual testing).

If you stop looking at boost::filesystem as a "sub-namespace", and instead look at boost:: as an "identity wrapper" for the individual projects filesystem::, thread::, program_options:: and whatnot, so that they look more "Boost-ish", the picture becomes clearer.

于 2013-02-06T09:50:55.113 回答
4

这是我在项目中使用的。我的主要规则是每个目录都是一个命名空间,每个文件都是一个类,只有极少数例外(有时我将辅助函数分组到命名空间的子目录中detail,但没有另一个嵌套命名空间)。

  1. 将您的整个项目保存在以您的项目命名的单个顶级命名空间中。

  2. 将每个实用程序组件保存在顶级名称空间内,但位于单独的目录中。这是我唯一一次不让我的命名空间与我的目录树重叠。

  3. 将项目中的每个可独立发布的组件保存在以组件命名的嵌套命名空间内。为方便起见,请提供一个以您的组件命名的标头,并在与您的命名空间对应的目录中或直接在项目的顶级目录中包含整个组件接口。

  4. 将每个组件的实现保存在嵌套的命名空间内detail。与类相反,命名空间没有对private成员的语言支持,但 Boost 中的约定是命名空间detail不应由用户代码直接调用。

不需要比project::component::detail::function()或更多project:::component::class.member()的嵌套。如果您提供促进 ADL 的完整接口,您可以在项目中重用组件函数作为类型function(x)变量,而不必担心名称冲突。xproject::component::class

请注意,用鲍勃叔叔的话来说:“重用的单位就是发布的单位”。每个组件都应该提供一堆连贯且相互依赖的类和函数。特别是,它应该为该组件提供一个完整的接口。C++ 语言将通过参数相关查找(ADL) 来支持这一点。请参阅 Herb Sutter 的旧专栏“命名空间和接口原则​​”。

reuse_if除非您在评论中提到的注意事项实际适用,否则两者的存在component和存在reusable可能是代码异味。组件应该是发布单元。如果您可以独立重用一段代码,请将其作为单独的组件。如果代码依赖于另一部分,请将其与其他代码一起发布。有关这些依赖关系,请参见 Sutter 的专栏。

于 2013-02-06T10:02:10.433 回答