在友元声明中使用限定名称的规则是什么?

What are the rules for using qualified names in friend declarations?

以下代码产生编译错误(至少在最新版本的 gcc 上):

namespace a {

class X { friend void ::foo(); };

}

错误是:

'void foo()' should have been declared inside '::'

如果我们从声明中删除::,根据标准,foo将被引入到命名空间a中(尽管它不会可见)。不需要在 a 中预先声明 foo。

我的问题是,鉴于上述情况,为什么要求在全局命名空间内预先声明?为什么名称 foo 没有成为全局命名空间的成员?我在标准中也找不到任何明确禁止这样做的段落,所以我很想知道。

您要查找的段落是 [dcl.meaning](C++11 中的 8.3 (1)):

(...) A declarator-id shall not be qualified except for the definition of a member function or static data member outside of its class, the definition or explicit instantiation of a function or variable of a namespace outside of its namespace, or the definition of an explicit specialization outside of its namespace, or the declaration of a friend function that is a member of another class or namespace. When the declarator-id is qualified, the declaration shall refer to a previously declared member of the class or namespace to which the qualifier refers (or, in the case of a namespace, of an element of the inline namespace set of that namespace).

(强调我的)这意味着你不能写

namespace a { }

void a::foo() { }

除非 a::foo 已经在命名空间内用不合格的声明符声明。朋友也不例外,朋友也不行。

[namespace.memdef] 中的脚注(C++11 中的 7.3.1.2 (3))更明确地提到了 friends 的特殊情况:

(...) If a friend declaration in a non-local class first declares a class or function95 the friend class or function is a member of the innermost enclosing namespace. (...)

95) This implies that the name of the class or function is unqualified.