我已阅读 [basic.lookup.unqual] 的标准部分,对此我感到困惑:
typedef int f;
namespace N {
struct A {
friend void f(A &);
operator int();
void g(A a) {
int i = f(a); // f is the typedef, not the friend function: equivalent to int(a)
}
};
}
请考虑上面的代码;我不明白为什么要命名f
是类型int
, 代替void f(A &)
。根据我的理解,名称查找应该找到void f(A &)
首先在类范围 A 中。如果在那里找不到名称,它将在外部名称空间中执行查找。显然,有一个名字void f(A &)
在班上A
正如标准所说:
一旦找到名称声明,名称查找就会结束
那么为什么名称指的是类型int
这里,是否有其他特殊规则?
首先,朋友宣言本身并不使f
对于名称查找可见,f
只能通过 ADL 找到。
首先在类或类模板 X 内的友元声明中声明的名称将成为 X 的最内层封闭命名空间的成员,但对于查找不可见(除了考虑 X 的参数相关查找之外),除非命名空间范围内的匹配声明是假如
从标准来看,[命名空间.memdef]/3,
友元声明本身并不使名称对非限定查找或限定查找可见。 [ 注意:如果在命名空间范围内提供了匹配的声明(在授予友谊的类定义之前或之后),则好友的名称将在其命名空间中可见。 — 尾注] 如果调用友元函数或函数模板,则可以通过名称查找来找到其名称,该名称查找考虑来自与函数参数类型关联的命名空间和类的函数 ([basic.lookup.argdep])。如果友元声明中的名称既不是限定的也不是模板 ID,并且声明是函数或详细类型说明符,则确定实体是否先前已声明的查找不应考虑最内部封闭命名空间之外的任何范围。
问题是要应用ADL,是否f(a)
是不是函数调用必须提前确定。
[基本.lookup.unqual]/3,
(强调我的)
用作函数调用的后缀表达式的非限定名称的查找在 [basic.lookup.argdep] 中描述。 [ 笔记:为了确定(在解析期间)表达式是否是函数调用的后缀表达式,应用通常的名称查找规则.
在此阶段,函数名称f
是不可见的并且类型名f
被发现,那么f(a)
被认为不是一个函数,那么 ADL 根本不会被应用。
因为表达式不是函数调用,所以依赖于参数的名称查找 ([basic.lookup.argdep]) 不适用,并且未找到友元函数 f。
顺便说一句:添加声明f
在命名空间范围内使函数名称f
可见和f(a)
将被视为函数调用(然后你会得到错误f
回报void
不能用于初始化i
). e.g.
typedef int f;
namespace N {
struct A;
void f(A &);
struct A {
friend void f(A &);
operator int();
void g(A a) {
int i = f(a); // f is the friend function now
}
};
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)