命名空间中的未命名命名空间

Com*_* 10 14 c++ namespaces

我被要求修改的一些代码看起来像这样:

namespace XXX {

namespace {

// some stuff

} // end of unnamed

// Some stuff within the scope of XXX

} // end of XXX
Run Code Online (Sandbox Code Playgroud)

我很难看到将未命名的命名空间嵌入另一个命名空间的优势(如果有的话),我正在考虑将其更改为:

namespace {

// some stuff

} // end of unnamed

namespace XXX {

// Some stuff within the scope of XXX

} // end of XXX
Run Code Online (Sandbox Code Playgroud)

任何意见将不胜感激.

小智 13

它确实有实际的好处.未命名的命名空间在其中隐藏来自不同翻译单元的名称.

上面的代码只是因为foo的定义在同一个翻译单元中.

假设main()和foo()的定义在不同的翻译单元中.它会编译,因为主文件包含声明的标题.但它不会链接,因为逻辑上没有X :: ((未命名的命名空间):: foo这样的东西.

  • _两个_示例都是这种情况。因此,您没有描述_差异_,也没有描述其中一种相对于另一种的好处。 (3认同)

Ale*_*nes 6

从全球观点来看,收益很少:如果从其他翻译单位的角度来看,两种方法都有相同的结果:匿名命名空间是不可见的(或者不能被引用).

从相同的翻译单元的角度来看,存在一个区别:您定义顶级命名空间的事实意味着您降低了导入在其他地方声明的命名空间冲突的概率,最常见的是全局命名空间(无命名空间)函数,考虑从ISO C继承的任何东西,如stdio.h或其他).

例如,如果您在该翻译单元中导入的全局标题具有"无名称空间"abort()并且您在翻译单元中声明了名称空间{abort(){...}},则会产生歧义,例如gcc会抛出编译错误:

error: call of overloaded ‘abort()’ is ambiguous
Run Code Online (Sandbox Code Playgroud)

现在,如果在命名命名空间中命名匿名命名空间,则会产生以下影响:

a)在命名空间内声明的函数没有歧义,因为它具有优先权:

namespace a { namespace { abort() {...} } }
Run Code Online (Sandbox Code Playgroud)

如果你有一个像:: whatever()这样的函数并且它引用了abort(),那么它将在它自己的命名空间中解析,因为它具有优先权.

b)你不会拥有:: abort()的全局链接,因为它不存在于翻译单元之外,与namespace {abort();相同.在顶层,但没有上面的潜在冲突.

在"b"中存在差异:它与命名空间a {abort();不同.因为它没有全局链接,所以你可以在没有冲突的情况下在另一个翻译单元中重新定义它.祝你好好试图链接两个定义名称空间的翻译单元{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
  }
}
Run Code Online (Sandbox Code Playgroud)

简而言之:两种方式都有相似之处,但存在差异.有人可能认为这不是很有用,但作为一种风格,它会先发制人地避免与全局命名空间的冲突.人们仍然可以争辩说,因为这些会在编译时捕获(希望,至少当签名完全匹配时),为什么还要麻烦.但是,如果您的项目是一个可移植的库,并且您的标头可能会受到污染,这取决于环境标头自身导入的内容,这是一个有用的概念,否则您的用户将不得不为您的系统修补您的库,或者您需要#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.
Run Code Online (Sandbox Code Playgroud)

...因为两个标题(来自例如不同的库)设法污染命名空间,我不能简单地修补别人的库.

C++命名空间解析了这一点,除非其他人不使用它,因此必须采取措施防止(这不是遗留代码的选项)或抵消它.


Lig*_*ica 5

好的,结果X::<anonymous>::foo()是可见的X::foo().我很惊讶.

所以,不,实际上没有什么好处.但是可能存在语义或文档含义.


原始答案

那相当取决于"东西",不是吗?

现有代码允许代码X具有"私有"其他内容,这些内容也在X但不能从以下位置访问X:

#include <iostream>

namespace X {
   namespace {
      void foo() { std::cout << "lol\n"; }
   }

   void bar() { foo(); }
}

int main()
{
   X::bar();
   // X::foo();  // can't do this directly  [edit: turns out we can!]
}
Run Code Online (Sandbox Code Playgroud)
  • 输出: lol\n

您提出的方法使整个翻译单元可以使用"私有内容":

#include <iostream>

namespace {
   void foo() { std::cout << "lol\n"; }
}

namespace X {
   void bar() { foo(); }
}

int main()
{
   X::bar();
   foo();     // works
}
Run Code Online (Sandbox Code Playgroud)
  • 输出: lol\nlol\n

  • *"所以,不,实际上没有什么好处."*.有*实用的好处.未命名的命名空间中的名称无法从其他翻译单元访问,即使它们具有外部链接,除非它们被声明为"static"或"const". (3认同)
  • @abhinav:是的,因为您正在从同一翻译(编译)单元访问它。 (2认同)