[namespace.qual] 相当简单:
1 如果 qualified-id 的 nested-name-specifier 指定了一个命名空间(包括 nested-name-specifier 的情况>是::,即指定全局命名空间),在命名空间范围内查找nested-name-specifier之后指定的名称。 template-id 的 template-argument 中的名称在整个 postfix-expression 出现的上下文中查找。 p>
2 对于命名空间 X 和名称 m,命名空间限定的查找集 S(X,m) 定义如下:让 S0(@987654327 @,m) 是X 中所有m 声明的集合和X (7.3.1) 的内联命名空间集合。如果 S0(X,m) 不为空,则 S(X,m) 为 S0(X,@987654337 @);否则,对于由 using -directives 在X 及其内联命名空间集中。
3 如果 S(X,m) 是空集,程序格式错误。否则,如果 S(X,m) 只有一个成员,或者如果引用的上下文是 using-declaration (7.3.3),则 S(X,@ 987654351@) 是m 的必需声明集。否则,如果 m 的使用不允许从 S(X,m) 中选择唯一声明,则程序是非良构的。
::foo 是一个 qualified-id 和 nested-name-specifier ::,因此名称 foo 在全局范围内查找。 p>
S0(::,foo) 包含 namespace foo 的单个声明,因为命名空间中没有 foo 的其他声明,并且它没有内联命名空间。由于 S0(::,foo) 不为空,因此 S(::,foo) 为 S0(::,@987654368 @)。 (请注意,由于 S0(::,foo) 不为空,因此不会检查 using 指令指定的命名空间。)
由于 S(::,foo) 只有一个元素,因此该声明用于 ::foo。
名称::foo::baz 因此是一个qualified-id,带有指定命名空间的nested-name-specifier ::foo。在命名空间::foo 中再次有一个baz 声明,因此名称::foo::baz 指的是class baz 声明。
您在 GCC 6+ 中观察到的行为实际上是一个错误,归档为 GCC PR 71173。
编辑:当 foo::baz 出现在全局范围内时查找它,a la:
foo::baz bang;
首先需要查找foo 作为非限定名称。 [basic.lookup.qual]/1 说这个查找只看到“名称空间、类型和模板,其特化是类型。” [basic.scope.namespace]/1 告诉我们命名空间成员及其作用域:
namespace-definition 的声明区域是它的namespace-body。 namespace-body 中声明的实体被称为命名空间的成员,这些声明引入到命名空间的声明区域的名称被称为命名空间的成员名称。命名空间成员名称具有命名空间范围。它的潜在范围包括从名称声明点开始的名称空间;对于每个指定成员命名空间的using-directive,成员的潜在范围包括该成员声明点之后的using-directive 潜在范围部分。
[basic.lookup.unqual]/4 告诉我们namespace foo 的声明是可见的:
在全局范围内使用的名称,在任何函数、类或用户声明的命名空间之外,应在其在全局范围内使用之前声明。
第 2 段说 class foo 在这里也可见:
using-directive 指定的命名空间中的声明在包含 using-directive 的命名空间中变得可见;见 7.3.4。出于 3.4.1 中描述的非限定名称查找规则的目的,由 using-directive 指定的命名空间中的声明被视为该封闭命名空间的成员。
由于发现了来自不同命名空间的两个不同foo 实体的声明,[namespace.udir]/6 告诉我们foo 的使用是错误的:
如果名称查找在两个不同的命名空间中找到一个名称的声明,并且这些声明没有声明相同的实体且没有声明函数,则该名称的使用是错误的。
我们对foo::baz 的名称查找在到达baz 之前就消失了。