首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >命名命名空间中的未命名命名空间

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

Stack Overflow用户
提问于 2013-01-08 01:31:03
回答 5查看 8.3K关注 0票数 20

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

代码语言:javascript
复制
namespace XXX {

namespace {

// some stuff

} // end of unnamed

// Some stuff within the scope of XXX

} // end of XXX

我很难看到将未命名的命名空间嵌入到另一个命名空间中的好处,我正在考虑将其更改为:

代码语言:javascript
复制
namespace {

// some stuff

} // end of unnamed

namespace XXX {

// Some stuff within the scope of XXX

} // end of XXX

任何意见都将不胜感激。

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2013-01-08 01:32:52

好吧事实证明X::::foo() is visible as X::foo(). .。我吃了一惊。

所以,不,没有什么实际的好处。不过,可能存在语义或文档方面的影响。

原始答案

好吧,这取决于“东西”,不是吗?

现有代码允许X中的代码具有也在X中但不能从X外部访问的“私有”其他内容

代码语言:javascript
复制
#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!]
}

  • 输出:lol\n

您提出的方法使整个翻译单元都可以使用这些“私有内容”:

代码语言:javascript
复制
#include <iostream>

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

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

int main()
{
   X::bar();
   foo();     // works
}

  • 输出:lol\nlol\n
票数 7
EN

Stack Overflow用户

发布于 2013-01-08 02:23:41

它确实有实际的好处。一个未命名的命名空间对不同的翻译单元隐藏了其中的名称。

上面的代码之所以有效,是因为foo的定义在相同的转换单元中。

假设()和foo()的定义在不同的转换单元中。它将被编译,因为主文件包含声明的头文件。但它不会链接,因为从逻辑上讲没有X::(未命名名称空间)::foo这样的东西。

票数 21
EN

Stack Overflow用户

发布于 2015-03-31 20:37:22

从全局的角度来看,几乎没有什么好处:如果从其他翻译单元的角度来看,这两种方法的结果是相同的:匿名名称空间是不可见的(或者不能被引用)。

从相同的转换单元的角度来看,这是有区别的:定义一个顶层名称空间的事实意味着您减少了导入在其他地方声明的名称空间冲突的可能性,最常见的冲突是全局名称空间(无名称空间的函数,可以考虑从ISO C继承的任何东西,比如来自stdio.h或其他任何东西)。

例如,如果您在该转换单元中导入的全局标头具有“无名称空间”的abort(),并且您在您的转换单元中声明了一个名称空间{ abort() { ...} },那么您将具有多义性,例如,gcc将抛出编译错误:

代码语言:javascript
复制
error: call of overloaded ‘abort()’ is ambiguous

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

a)在名称空间中声明的函数没有歧义,因为它具有优先级:

代码语言:javascript
复制
namespace a { namespace { abort() {...} } }

如果你有一个函数,比如::at (),并且它引用了abort(),它将在它自己的命名空间中解析,因为它有优先权。

b)你不会有一个::abort()的全局链接,因为它不存在于翻译单元之外,与toplevel中的命名空间{ abort();}相同,但没有上面的潜在冲突。

"b“的区别在于:它不同于名称空间a{ abort();},因为它不会有全局链接,所以您可以在另一个翻译单元中重新定义它,而不会发生冲突。祝您好运,尝试链接两个都定义名称空间的翻译单元{ abort() { ... }} ...

所以你得到的就是你想要的:

代码语言:javascript
复制
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上编写了很多程序,有时我必须做一些事情,比如:

代码语言:javascript
复制
#include <headerA.h>
#define symbol symbolB
#include <headerB.h>
// or some crap alike. And I have linker problems with above.

..。因为这两个头文件(例如来自不同的库)都设法污染了名称空间,而我不能简单地修补别人的库。

C++名称空间解决了这个问题,除非其他人不使用它,因此您必须采取措施防止(这不是遗留代码的选项)或抵消它。

票数 7
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/14201023

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档