嵌套匿名命名空间

5
在C++中,以下方式声明嵌套匿名命名空间是合法的:

namespace {
    namespace {
        struct Foo
        {
        };
    }
}

namespace {    
    struct Foo // SAME IDENTIFIER AS <unnamed>::<unnamed>::Foo!!!
    {
    };
}

然而,如何使用显式类型的Foo声明标识符以避免歧义呢?

编辑-- 对于那些不阅读问题的人。

p.s. 我没有使用这种结构的意图,但我需要了解是否可能在有人发现合法用途的情况下消除Foo的歧义。我的编译器扩展程序需要处理所有情况。


1
"::Foo" 是在 GCC 4.7.2 中的第二个。我不确定如何指定第一个,因为只有 "Foo" 是模糊的。 - chris
5
虽然匿名命名空间的嵌套是可以接受的,但我认为在不同层次的匿名命名空间中放置多个相同名称将是极其不明智的。匿名命名空间旨在作为全局命名空间的文件本地版本,不应被滥用。 - Kerrek SB
@KerrekSB,我需要知道是否可能让我的GCC插件处理所有情况。我从未这样做过嵌套命名空间,也没有这样的意图。 - Zach Saw
2个回答

4
C++标准在7.3.1.1p1中已经明确说明了以下内容:
未命名的命名空间定义的行为就像是被以下替换:
inline(opt) namespace unique { /* empty body */ }
using namespace unique ;
namespace unique { namespace-body }

当且仅当 inline 出现在未命名的命名空间定义中时,所有在一个翻译单元中出现的 unique 都将被替换为相同的标识符,并且该标识符与整个程序中的所有其他标识符都不同。

因此,从上面的内容我们可以知道,您的代码实际上是这样翻译的:

namespace unique1 {}
using namespace unique1;
namespace unique1 {
    namespace unique2 {}
    using namespace unique2;
    namespace unique2 {

        struct Foo
        {
        };

    }
}

namespace unique3 {}
using namespace unique3;
namespace unique3 {

    struct Foo
    {
    };

}

因此,你的第一个Foo只能在namespace unique1内访问,而第二个Foo可以通过using namespace unique3;在全局命名空间中访问。我之前的翻译有误,已被下面的评论纠正。
然后从7.3.4p4开始:
对于未经限定的查找(3.4.1),使用指令是可传递的:如果作用域包含一个使用指令,该指令提名了一个第二个命名空间,该命名空间本身包含使用指令,则效果就像第二个命名空间的使用指令也出现在第一个命名空间中一样。
因此,当你引用Foo时,它可能意味着unique1::unique2::Foounique3::Foo,这是一个错误。请注意,另一个答案说:has hidden unique name that cannot be accessed。这是不正确的,由于使用指令,两个名称都是可见的,只是不能同时使用。
但是,通过在Foo之前加上作用域解析运算符::,你可以访问unique3::Foo,因为根据以下内容:
对于命名空间X和名称m,命名空间限定的查找集合S(X,m)定义如下:让S0(X,m)成为X和X的内联命名空间集合中m的所有声明的集合(7.3.1)。如果S0(X,m)不为空,则S(X,m)为S0(X,m);否则,S(X,m)是由X中使用指令提名的所有名称空间Ni的S(Ni,m)的并集,并且它的内联命名空间集。
强调部分说X中的使用指令,在你的情况下意味着using namespace unique1;using namespace unique3;,因此命名空间限定的查找集合看起来像这样:S(unique3::Foo),这意味着unique1::unique2::Foo不包含在集合中,因此不是一个错误。

但是这个 `namespace { namespace { int foo1() { return 0; } } int foo2() { return 1; } } int foo3() { return 2; }int main() { cout << foo1() << foo2() << foo3() << "\n"; }` 可以正常输出012,没有问题 http://ideone.com/CbeVUu - PiotrNycz
@PiotrNycz:也许我的使用指令的理解是错误的。谢谢您指出来。 - Jesse Good
using 指令将所有内容放置在当前命名空间中。因此,下一个向上一级的 using 也会拉取先前拉取的所有内容。因此,可以访问所有内容。 - Nikos C.
我也认为第二个顶级命名空间名称将是unique1,而不是unique3,“翻译单元中所有唯一的出现都将被相同的标识符替换”。 - garph0

0

是的,这是完全合法的,因为它不违反任何规定。

未命名命名空间在概念上等同于:

namespace <09FD8E6E-2DB6-4517-B62D-3B5A657DCC82>
{
  // ....
}

这意味着每个未命名的命名空间都有一个隐藏的唯一名称,无法访问。


@KerrekSB:不,因为问题是“如何使用显式类型的Foo声明标识符以避免歧义?”第一部分更像是一个断言,给出了“它是”而不是“它是吗”的语气,并且没有问号... - user405725
@VladLazarenko:哦,抱歉,我看错了!你说得完全正确。 - Kerrek SB
我反驳你关于使用 namespace { struct Foo{}; } Foo foo; 无法访问的观点。 - chris
4
未命名命名空间带有隐式的using指令,以便其成员可以在命名空间外部访问。因此,成员可以被正常访问。 - Nikos C.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接