从全局视角来看,两种方法都没有太多好处:从其他翻译单元的角度来看,这两种方法的结果相同:匿名命名空间是不可见的(或无法引用)。
从同一翻译单元的角度来看,有所不同:你定义一个顶层命名空间意味着你减少了在其他地方声明的命名空间冲突的可能性,最常见的就是全局命名空间(无命名空间函数,想象一下从ISO C继承的任何内容,比如stdio.h或其他内容)。
例如,如果你在该翻译单元中导入的全局头文件具有“无命名空间”的abort()函数,并且你在你的翻译单元中声明了一个命名空间 { abort() { ...} },那么就会产生歧义,例如gcc将抛出编译错误:
error: call of overloaded ‘abort()’ is ambiguous
现在,如果你在命名空间内部命名一个匿名命名空间,则会产生以下影响:
a) 对于在该命名空间内声明的函数,不存在歧义,因为它具有优先权:
namespace a { namespace { abort() {...} } }
如果您有一个像a::whatever()这样的函数,并且它引用了abort(),那么它会在自己的命名空间中解析,因为它具有优先权。
b) 对于a::abort(),您不会有全局链接,因为它不存在于翻译单元之外,与顶级的namespace { abort(); }相同,但没有上述潜在冲突。
而在"b"中存在着区别: 它并不等同于只是namespace a { abort(); },因为它没有全局链接,所以您可以在另一个翻译单元中重新定义它而没有冲突。祝你尝试链接两个定义namespace a { abort() { ... } }的翻译单元好运...
因此,您将获得您想要的结果:
namespace a { // you have a named space, so you don't have conflicts with the nameless one
namespace { // but you have local visibility and linkage
whatever(); // for this
}
}
简而言之:这两种方法有相似之处,但也有区别。有人可能会认为这并不是非常有用,但作为一种风格,它可以预防与全局命名空间的冲突。有人可能会说,既然这些问题在编译时就能被捕获(希望至少在签名完全匹配时),那么为什么要费心呢?但如果您的项目是一个可移植的库,您的头文件可能会受到环境头文件导入的影响而被污染,那么这是一个有用的概念,否则您的用户将不得不为其系统修补您的库,或者您需要在各个地方使用 #ifdef。
我经常在 ISO/ANSI C 99 上编程,偶尔需要做一些这样的事情:
#include <headerA.h>
#define symbol symbolB
#include <headerB.h>
// or some crap alike. And I have linker problems with above.
由于两个头文件(例如来自不同库)都污染了命名空间,我无法简单地修补别人的库。
C++ 命名空间可以解决这个问题,除非有人不使用它,因此你必须采取措施来防止(对于旧代码来说不是一个选项)或对抗它。
XXX::some_function();
,而使用你的提议,则需要像这样调用some_function();
。没有XXX::
的调用可能更容易出错,因为你可能会意外地从全局范围调用外部函数。 - Grim Fandango