全局未命名的命名空间歧义与嵌套的未命名的命名空间歧义

OMG*_*chy 3 c++ namespaces ambiguous

请考虑以下两个代码段:

片段A.

#include <iostream>

namespace
{
    bool foo = false;
}

bool foo = true;

int main()
{
    std::cout << foo << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

代码片段B.

#include <iostream>

namespace A
{
    namespace
    {
        bool foo = false;
    }

    bool foo = true;
}

int main()
{
    std::cout << A::foo << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

Snippet A中,foo里面的用法int main()是模棱两可的,而在Snippet B中则不然.为什么会这样?


相关:匿名命名空间歧义

T.C*_*.C. 5

未命名的命名空间的行为在§7.3.1.1[namespace.unnamed]/p1中指定:

一个不愿透露姓名的命名空间定义的行为就好像它被取代

inline_opt namespace unique { /* empty body */ }
using namespace unique ;
namespace unique { namespace-body }
Run Code Online (Sandbox Code Playgroud)

其中inline当且仅当它出现在出现 未命名的名称空间定义,所有出现unique在翻译单元由相同的标识符代替,并且该标识符从在整个程序中所有其他标识符不同.

特别要注意,未命名的命名空间内的声明通过using-directive 在周围的作用域中可见using namespace unique;.

在Snippet A中,foo是不合格的,因此编译器执行非限定名称查找(§3.4.1[basic.lookup.unqual]).这里的相关内容是子条款的第2段:

2从由指定的命名空间中的声明使用指示符 在命名空间变得可见包围使用指示符 ; 见7.3.4.出于3.4.1中描述的非限定名称查找规则的目的,using-directive指定的命名空间中的声明 被视为该封闭命名空间的成员.

因此,非限定名称查找会查找两个声明foo,并且名称不明确.

在Snippet B中,A::foo是合格的,因此适用限定名称查找规则.由于A是名称空间,适用的子条款是§3.4.3.2[namespace.qual].与此相关,该规则在该子条款第2款中规定:

对于命名空间X和名称m,命名空间限定的查找集 S(X,m)定义如下:S'(X,m)设为min 的所有声明的X集合和X (7.3.1)的内联命名空间集合.如果S'(X,m)不是空的,S(X,m)S'(X,m); 否则, S(X,m)是联盟S(Ni,m)的所有命名空间Ni提名using指令X其内嵌的命名空间集中.

换句话说,只有在指定的命名空间及其内联命名空间集中找不到该名称时,限定名称查找才会考虑使用指令指定的命名空间.这里,名称foo在命名空间中找到A,因此不考虑由using-directive指定的未命名命名空间,并且没有歧义.

如果你::foo不是foo在Snippet A中编写,那么将适用合格的查找规则,并且再次没有歧义.