避免过度使用命名空间

Max*_*xpm 7 c++ namespaces organization ambiguity

我的库使用了几个嵌套的命名空间,如下所示:

Library name
    Class name 1
    Class name 2
    Class name 3
    [...]
    Utilities
        Class name 1
            [...]
        Class name 2
            [...]
        Class name 3
            [...]
        [...]
Run Code Online (Sandbox Code Playgroud)

"Utilities"命名空间包含对每个类的有用扩展,这些扩展不保证包含在实际类本身中.

"库名"的命名空间是必要的,因为它避免了与其他库的广泛的冲突,在"工具"命名空间是必要的,以避免歧义,从出现的类型,像这样的事情,而且里面的"类名"的命名空间避免之间的名称冲突为类似的类编写的实用程序

尽管如此,它在实践中仍然是一个巨大的麻烦.举例来说,例如:

MyLibrary::MyContainer<int> Numbers = MyLibrary::Utilities::MyContainer::Insert(OtherContainer, 123, 456);
// Oh God, my eyes...
Run Code Online (Sandbox Code Playgroud)

这让我觉得我做错了.有没有更简单的方法来保持组织,直观和明确的事情?

jal*_*alf 12

看看标准库(或boost)的组织方式.几乎所有这些都在单个std命名空间内.通过将所有内容放在其自己的命名空间中,几乎没有什么可获得的.

Boost将大部分内容放入其中boost,而主要库则获得单个子名称空间(例如boost::mpl,或者boost::filesystem).库通常aux为内部实现细节定义单个子名称空间.

但是,您通常不会看到深层次或细粒度的命名空间层次结构,因为它们使用起来很痛苦,而且它们几乎没有任何好处.

以下是一些好的经验法则:

与特定类相关的辅助函数应与类在同一名称空间中,以使ADL能够工作.然后,在调用它时,根本不需要限定辅助函数的名称.(就像你可以调用sort而不是std::sort在定义的迭代器上调用std).

对于其他一切,请记住命名空间的目的是避免名称冲突,而不是其他.因此,所有的图书馆应该是一个命名空间,以避免用户代码冲突,但该命名空间中,没有技术需要进一步的子名称,除非你打算引进冲突的名字.

您可能希望将库的内部分隔为子命名空间,因此用户不会意外地从主命名空间中选择它们,类似于Boost的aux.

但一般来说,我建议尽可能少的嵌套命名空间.

最后,我倾向于为我的命名空间使用简短,易于类型和易于阅读的名称(同样,这std是一个很好的例子.简而言之,几乎总是没有进一步嵌套命名空间,所以你不必经常编写它,所以它不会使你的源代码混乱太多.)

关于辅助函数和ADL的第一条规则将允许您的示例重写为:

MyLibrary::MyContainer<int> Numbers = Insert(OtherContainer, 123, 456);
Run Code Online (Sandbox Code Playgroud)

然后我们可以重命名MyLibrary为,比方说Lib:

Lib::MyContainer<int> Numbers = Insert(OtherContainer, 123, 456);
Run Code Online (Sandbox Code Playgroud)

而且你的事情很容易管理.

不同类的类似实用程序函数之间不应存在任何冲突.C++允许您重载函数和专门化模板,以便您可以同时拥有一个Insert(ContainerA)Insert(ContainerB)相同的命名空间.

当然,只有在您实际拥有其他嵌套命名空间时,才能实现命名空间和类之间的冲突.

请记住,在Library命名空间中,您可以单独指定引入的名称.因此,您可以避免名称冲突,而不是创建任何冲突的名称.将用户代码与库代码分开的命名空间很重要,因为这两者可能不了解彼此,因此可能会无意中发生冲突.

但是在你的图书馆里,你可以给出一切非冲突的名字.

  • 我想投票五次。我使用过多个具有多余“Utilities”[或类似]嵌套命名空间的库,它们总是感觉原始开发人员只是讨厌重载和 ADL,并希望确保编译器无法使用它。 (2认同)

小智 7

如果有什么伤害,请停止这样做.绝对不需要在C++中使用深层嵌套的命名空间 - 它们不是建筑设备.我自己的代码总是使用单级命名空间.

如果您坚持使用嵌套命名空间,则始终可以为它们创建短别名:

namespace Util = Library::Utility;
Run Code Online (Sandbox Code Playgroud)

然后:

int x = Util::somefunc();   // calls Library::Utility::somefunc()
Run Code Online (Sandbox Code Playgroud)