关于友元函数定义和命名空间范围

Regarding friend function definition and namespace scopes

我正在阅读这篇文章 blog post section,并且尝试使用提供的代码段。

namespace N {
// 2
class A {
friend void f(A) {} // 1
};
}

如果我没理解错的话,// 1中的定义会在// 2所在的位置注入名称f。 但是,它只能通过依赖于参数的查找获得。很好。

post中有一句话引起了我的注意:

7.3.1.2/3 Namespace member definitions [namespace.memdef]p3

在命名空间中首次声明的每个名称都是该命名空间的成员。如果非本地 class 中的友元声明首先声明了 class、函数、class 模板或函数模板,则友元是最内层封闭命名空间的成员。朋友声明本身不会使名称对非限定查找 (3.4.1) 或限定查找 (3.4.3) 可见。

请注意,没有任何地方声明友元声明引入的名称必须与声明 and/or 的 class 的名称有任何特定关系,或任何特定关系class(就此而言)。

据此,我认为以下代码段是有效的:

namespace N {
struct A {
};

struct B {
  friend void f(A) {
}
};

int main() {
  N::A a;
  f(a);
}

但它被 GCC7 和 Clang 4 都拒绝了。

t.cpp:19:3: error: ‘f’ was not declared in this scope

有趣的是,当我尝试用 N::B 对象调用 f 时,出现以下错误:

t.cpp:12:6: error: could not convert ‘b’ from ‘N::B’ to ‘N::A’

所以这是我的问题:

不应该 f(A) 通过 ADL 检测到吗?由于两个 classes 都在名称空间中,所以我不明白为什么会失败。我查看了关于朋友的标准部分,但没有找到相关部分。

我想知道 f(A) 是在哪个范围内注入的,因为当我尝试通过调用 f(B).

给出错误的参数类型时,GCC 能够找到它

来自 cppreference/cpp/language/friend:

A name first declared in a friend declaration within class or class template X becomes a member of the innermost enclosing namespace of X, but is not accessible for lookup (except argument-dependent lookup that considers X) unless a matching declaration at the namespace scope is provided - see namespaces for details.


来自 cppreference/cpp/language/namespace:

Names introduced by friend declarations within a non-local class X become members of the innermost enclosing namespace of X, but they do not become visible to lookup (neither unqualified nor qualified) unless a matching declaration is provided at namespace scope, either before or after the class definition. Such name may be found through ADL which considers both namespaces and classes.


这与您的示例一致 - f 采用 A,它与封闭的 class.

类型不同

如果您将示例更改为...

namespace N {
struct A {
};

struct B {
  friend void f(B) {
}
};

int main() {
  N::B b;
  f(b);
}

...它将编译。


相关标准报价:

.3 [class.friend]

A friend of a class is a function or class that is given permission to use the private and protected member names from the class. [...] A function can be defined in a friend declaration of a class if and only if the class is a non-local class ([class.local]), the function name is unqualified, and the function has namespace scope. [...] Such a function is implicitly an inline function. A friend function defined in a class is in the (lexical) scope of the class in which it is defined. A friend function defined outside the class is not ([basic.lookup.unqual]).