【发布时间】:2017-09-06 11:15:04
【问题描述】:
我正在阅读此blog post section,并尝试使用提供的 sn-p。
namespace N {
// 2
class A {
friend void f(A) {} // 1
};
}
如果我理解正确,// 1 中的定义将在// 2 所在的位置注入名称f。
但是,它只能通过依赖于参数的查找获得。很好。
帖子里有一句话引起了我的注意:
7.3.1.2/3 命名空间成员定义 [namespace.memdef]p3
在命名空间中首先声明的每个名称都是该命名空间的成员。如果非本地类中的友元声明首先声明了一个类、函数、类模板或函数模板,则友元是最内层封闭命名空间的成员。友元声明本身不会使名称对非限定查找 (3.4.1) 或限定查找 (3.4.3) 可见。
请注意,没有任何地方声明由朋友声明引入的名称必须与声明和/或定义它的类的名称有任何特定关系,或者与该类有任何特定关系(就此而言)。
据此,我认为以下 sn-p 是有效的:
namespace N {
struct A {
};
struct B {
friend void f(A) {
}
};
int main() {
N::A a;
f(a);
}
但它被 GCC7 和 Clang 4 拒绝。
t.cpp:19:3: 错误:'f' 未在此范围内声明
有趣的是,当我尝试使用 N::B 对象调用 f 时,出现以下错误:
t.cpp:12:6: 错误:无法将“b”从“N::B”转换为“N::A”
这是我的问题:
不应该通过 ADL 检测到 f(A) 吗?由于这两个类都在命名空间中,我不明白为什么会失败。我在标准中查看了关于朋友的部分,但没有找到相关部分。
我想知道f(A) 是在哪个范围内注入的,因为当我尝试通过调用f(B) 给出错误的参数类型时,GCC 能够找到它。
【问题讨论】:
标签: c++ friend argument-dependent-lookup