从全局角度来看几乎没有什么好处:如果从其他翻译单元的角度来看,两种方法的结果相同:匿名命名空间是不可见的(或无法引用)。
从同一个翻译单元的角度来看,有一个区别:定义顶级命名空间这一事实意味着您减少了导入在其他地方声明的命名空间冲突的可能性,最常见的是全局命名空间(无命名空间的函数,想想从 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”的区别在于:它与命名空间 a { abort(); 不同。 } 因为它没有全局链接,所以你可以在另一个翻译单元中重新定义它而不会发生冲突。祝你好运尝试链接两个定义命名空间 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
}
}
简而言之:两种方式都有相似之处,但也有区别。有人可能会说这不是很有用,但作为一种风格,它会抢先避免与全局命名空间发生冲突。人们仍然可以争辩说,既然这些会在编译时被捕获(希望至少在签名完全匹配时),为什么还要麻烦。但是,如果您的项目是一个可移植的库,并且您的头文件可能会根据环境头文件本身导入的任何内容而受到污染,那么这是一个有用的概念,否则您的用户将不得不为他们的系统修补您的库,或者您需要#ifdefs到处都是。
我在 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++ 命名空间解决了这个问题,除非其他人不使用它,所以你必须采取措施防止(这不是遗留代码的选项)或抵消它。