C++ 在朋友声明中使用限定名的规则是什么?

C++ 在朋友声明中使用限定名的规则是什么?,c++,namespaces,friend,C++,Namespaces,Friend,以下代码产生编译错误(至少在最新版本的gcc上): 错误是: 'void foo()' should have been declared inside '::' 如果我们从声明中删除::,根据标准,foo将被引入命名空间a(尽管它不可见)。不需要在a中预先删除foo 我的问题是,鉴于上述情况,为什么需要在全局名称空间中预先声明?为什么名称foo没有成为全局名称空间的成员?我在标准中找不到任何明确禁止这一点的段落,因此我很想知道。您要查找的段落是[dcl.means](C++11中的8.3(1

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

错误是:

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


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

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

(…)声明器id不应被限定,除非其类外的成员函数或静态数据成员的定义,其命名空间外的命名空间的函数或变量的定义或显式实例化,或其命名空间外的显式专门化的定义,或者是作为另一个类或命名空间的成员的友元函数的声明当声明符id被限定时,声明应引用该限定符所引用的类或命名空间的先前声明的成员(或者,在命名空间的情况下,该命名空间的内联命名空间集的元素)

这意味着你不能写作

namespace a { }

void a::foo() { }
除非
a::foo
已在命名空间中使用非限定声明符声明。既然朋友也不例外,你也不能为朋友这样做

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

(…)如果非局部类中的友元声明首先声明一个类或函数95,则友元类或函数是最内层封闭命名空间的成员。(……)

95)这意味着类或函数的名称是非限定的

namespace a { }

void a::foo() { }