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

3

考虑以下两个代码片段:

代码片段 A

#include <iostream>

namespace
{
    bool foo = false;
}

bool foo = true;

int main()
{
    std::cout << foo << std::endl;
}

片段 B

#include <iostream>

namespace A
{
    namespace
    {
        bool foo = false;
    }

    bool foo = true;
}

int main()
{
    std::cout << A::foo << std::endl;
}

代码片段A中,fooint main()中的用法是模糊的,而在代码片段B中则不是。为什么会这样?

相关: 匿名命名空间的歧义


1
A是未限定查找;B是限定查找。规则不同。 - T.C.
我同意T.C的观点,实际上,如果你只是在命名空间A中添加void bar(){ std::cout << foo << '\n'; },那么相同的问题也会出现,但要注意添加的位置是相关的。例如,这个可以工作,而这个则不行 - WhozCraig
1个回答

5
未命名命名空间的行为在§7.3.1.1 [namespace.unnamed]/p1中有明确规定:

An unnamed-namespace-definition behaves as if it were replaced by

inline_opt namespace unique { /* empty body */ }
using namespace unique ;
namespace unique { namespace-body }

where inline appears if and only if it appears in the unnamed-namespace-definition, all occurrences of unique in a translation unit are replaced by the same identifier, and this identifier differs from all other identifiers in the entire program.

特别注意,未命名命名空间内的声明通过 using namespace unique; 的 using-directive 在周围作用域中可见。
在 Snippet A 中,foo 是未限定的,因此编译器执行未限定名称查找(§3.4.1 [basic.lookup.unqual])。这里相关的是子句的第二段:
2 由 using-directive 提名的命名空间中的声明在封闭 using-directive 的命名空间中变得可见;参见 7.3.4。对于描述在 3.4.1 中的未限定名称查找规则,由 using-directive 提名的命名空间中的声明被认为是该封闭命名空间的成员。
因此,未限定名称查找找到了 foo 的两个声明,导致名称不明确。
在 Snippet B 中,A::foo 是限定的,因此应用限定名称查找规则。由于 A 是一个命名空间,适用的子句是 §3.4.3.2 [namespace.qual]。在这里相关的规则在该子句的第二段中指定:
对于命名空间X和名称m,命名空间限定查找集合S(X,m)的定义如下:设S'(X,m)X中所有声明m的集合以及X的内联命名空间集合(7.3.1)。如果S'(X,m)非空,则S(X,m)等于S'(X,m);否则,S(X,m)X及其内联命名空间集合中所有由using-directive提名的命名空间Ni的并集S(Ni,m)
换句话说,限定名称查找只有在指定的命名空间及其内联命名空间集合中找不到该名称时,才考虑由using-directive提名的命名空间。在这里,名称foo在命名空间A中找到,因此不考虑由using-directive提名的未命名命名空间,也不存在歧义。
如果在代码段A中写入::foo而不是foo,则将应用限定查找规则,这样就不会存在歧义。

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