关于友元函数定义和命名空间范围
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);
}
...它将编译。
相关标准报价:
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]).
我正在阅读这篇文章 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)
.
来自 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 ofX
, but is not accessible for lookup (except argument-dependent lookup that considersX
) 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 ofX
, 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);
}
...它将编译。
相关标准报价:
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]).