21

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

namespace XXX {

namespace {

// some stuff

} // end of unnamed

// Some stuff within the scope of XXX

} // end of XXX

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

namespace {

// some stuff

} // end of unnamed

namespace XXX {

// Some stuff within the scope of XXX

} // end of XXX

任何意见将不胜感激。

4

5 回答 5

21

它确实有实际的好处。一个未命名的命名空间将名称隐藏在其中以防止不同的翻译单元

上面的代码之所以有效,只是因为 foo 的定义在同一个翻译单元中。

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

于 2013-01-07T18:23:40.547 回答
7

好的,结果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!]
}
  • 输出:lol\n

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

#include <iostream>

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

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

int main()
{
   X::bar();
   foo();     // works
}
  • 输出:lol\nlol\n
于 2013-01-07T17:32:52.263 回答
7

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

从同一个翻译单元的角度来看,有一个区别:定义顶级命名空间这一事实意味着您减少了导入在其他地方声明的命名空间冲突的可能性,最常见的是全局命名空间(无命名空间函数,想想从 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++ 命名空间解决了这个问题,除非其他人不使用它,因此必须采取措施防止(这不是遗留代码的选项)或抵消它。

于 2015-03-31T12:37:22.267 回答
1

在命名命名空间中使用未命名命名空间的好处之一是防止依赖于参数的查找 (ADL)。实际上,如果您在同一个命名空间中定义类型和函数,您可能会遇到不良影响。下面的例子说明了这个问题:

假设我们有一个简单的头文件,如下所示,我们在其中为我们的命名空间myfunction中的自定义类型定义了一个通用函数。mytypemynamespace

//header.h
namespace mynamespace {
    struct mytype {};

    static void myfunction(mytype){}
}

现在,在另一个文件test.cpp中,我们想要覆盖myfunction特定目的(例如打印调试信息,做额外的事情,I18N...),而不改变我们程序的其余部分。以下代码不会与我们的头文件冲突,因为它是不同的命名空间,即全局命名空间。

//test.cpp
#include "header.h"

static void myfunction(mynamespace::mytype){}

int main(){
    mynamespace::mytype val = {};
    //error: call of overloaded 'myfunction(mynamespace::mytype&)' is ambiguous
    myfunction(val);
}

令人惊讶的是,由于 ADL,对上面的调用myfunction是模棱两可的并且无法编译。为了解决您的问题,您可以通过匿名命名空间来阻止 ADL。

//header.h
namespace mynamespace {
    struct mytype {};

    //OK prevents ADL
    namespace {
        static void myfunction(mytype){}
    }
}
于 2019-10-22T15:16:53.533 回答
0

一个简单的好处是,从命名命名空间中的匿名命名空间,可以直接访问命名命名空间的东西:

namespace foo {
    class Bar;

    namespace {
        void Baz() {
            Bar bar;  // no need to specify the foo namespace 
            …
        }
    }

    …
}

代替:

class foo::Bar;

namespace {
    void Baz() {
        foo::Bar bar;
        …
    }
}

namespace foo {
    …
}
于 2021-12-30T19:06:53.223 回答