我的库使用了几个嵌套的命名空间,如下所示:
Library name
Class name 1
Class name 2
Class name 3
[...]
Utilities
Class name 1
[...]
Class name 2
[...]
Class name 3
[...]
[...]
“Utilities”命名空间包含对不保证包含在实际类本身中的每个类的有用扩展。
“库名称”命名空间是必需的,因为它避免了与其他库的广泛冲突,“实用程序”命名空间是必要的,以避免由things like this引起的歧义类型,以及内部的“类名”命名空间它避免了为类似类编写的实用程序之间的名称冲突。
尽管如此,在实践中仍然是一个巨大的麻烦。请采取以下措施,例如:
MyLibrary::MyContainer<int> Numbers = MyLibrary::Utilities::MyContainer::Insert(OtherContainer, 123, 456);
// Oh God, my eyes...
这让我觉得我做错了。有没有更简单的方法来保持组织,直观和明确的事情?
答案 0 :(得分: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);
然后我们可以将MyLibrary
重命名为Lib
:
Lib::MyContainer<int> Numbers = Insert(OtherContainer, 123, 456);
你可以轻松管理。
不同类的类似实用程序函数之间不应存在任何冲突。 C ++允许您重载函数和专门化模板,这样您就可以在同一名称空间中同时拥有Insert(ContainerA)
和Insert(ContainerB)
。
当然,只有当你真正拥有其他嵌套命名空间时,才能实现命名空间和类之间的冲突。
请记住,在Library
命名空间内, 单独指定引入了哪些名称。因此,您可以避免名称冲突,而不是创建任何冲突的名称。将用户代码与库代码分开的命名空间非常重要,因为这两者可能不了解彼此,因此可能会无意中发生冲突。
但是在你的图书馆里,你可以给所有非冲突的名字。
答案 1 :(得分:7)
如果有什么伤害,请停止这样做。绝对不需要在C ++中使用深层嵌套的命名空间 - 它们不是建筑设备。我自己的代码总是使用单级命名空间。
如果您坚持使用嵌套命名空间,则始终可以为它们创建短别名:
namespace Util = Library::Utility;
然后:
int x = Util::somefunc(); // calls Library::Utility::somefunc()
答案 2 :(得分:3)
头文件中的声明要求命名空间不要污染全局命名空间:
MyLibrary::Utilities::MyContainer<int> Numbers;
但是在源文件中你可以使用:
using namespace MyLibrary::Utilities;
...
MyContainer<int> Numbers;
Numbers.Insert(OtherContainer, 123, 456);
答案 3 :(得分:2)
完全限定名称对我来说实际上看起来并不坏,但我喜欢在方法和类名中明确表示。但是using
可以解决问题:
您可能会在源文件的全局范围内使用using namespace MyLibrary
,从而实现:
MyContainer<int> Numbers = Utilities::MyContainer::Insert(OtherContainer, 123, 456);
然后您可以导入所需的特定功能:
using MyLibrary::Utilities::MyContainer::Insert
然后
MyContainer<int> Numbers = Insert(OtherContainer, 123, 456);