3 回答
TA贡献1828条经验 获得超4个赞
当您friend
在类中声明具有非限定ID的函数时,它将在最近的封闭命名空间范围内命名一个函数。
如果该函数先前未声明,则该friend
声明不会使该函数在该范围内可见以进行常规查找。它确实使声明的函数对依赖于参数的查找可见。
许多注释中都强调了这一点,但是在7.3.1.2/3(ISO/IEC 14882:2011的定义)中有明确的声明:
首先在名称空间中声明的每个名称都是该名称空间的成员。如果
friend
非本地类中的声明首先声明了一个类或函数,则该朋友类或函数是最内部封闭的命名空间的成员。直到通过在名称空间范围中提供匹配的声明(在授予友谊的类定义之前或之后),才可以通过非限定查找(3.4.1)或限定查找(3.4.3)找不到朋友的名称。如果调用了朋友函数,则可以通过名称查找来找到其名称,该名称查找考虑了来自与函数参数类型(3.4.2)相关联的名称空间和类中的函数。如果friend
声明中的名称既不合格也不是template-id并且声明是一个函数或一个elaborated-type-specifier,则用于确定该实体先前是否已声明的查找将不考虑最内层封闭名称空间之外的任何作用域。
TA贡献1818条经验 获得超7个赞
“ C ++编程语言第三版(Stroustrap)”:p279:
I.“像成员声明一样,朋友声明不会将名称引入封闭范围”
II。“朋友类必须事先在封闭范围内声明或在非类范围内定义,以立即将声明其为朋友的类封闭起来”
III。“可以像朋友类一样显式声明一个朋友函数,也可以通过其参数类型(第8.2.6节)找到它,就好像在紧随其类的非类作用域中声明它一样。”
IV。“因此,应该在封闭范围内显式声明一个朋友函数,或者接受其类的参数。否则,不能调用该朋友。例如:”
//no f() here
void g();
class X{
friend void f(); //useless
friend void g(); //can be found because it is declared outside of class scope
friend void h(const X&); //can be found because the arguments access class members
};
void f() { } //enemy of X :)
但是在您的情况下,还有更多与名称空间有关的问题,因为如果将正确的声明放入foo中,例如:
namespace foo{
struct bar{
friend void baz(const &bar){};
void call_friend();
}
}
不编译。但是,如果在foo外部声明它,则它就像是一种魅力。现在考虑一下,实际上,全局,局部,结构和类实际上是名称空间。现在得出结论,baz(const &)在全局范围中隐式定义了。
这样编译:
namespace foo{
struct bar{
friend void baz(const bar&){};
void call_friend();
};
}
int main(){
foo::bar k;
baz(k);
return 0;
}
因此,存在两个问题:
除非IV,否则好友声明不会在封闭范围内引入名称。因此,原始程序找不到baz(),因为尚未正确声明它。
如果为IV,即ADL,则该函数在foo中找到,但由于ADL而无法作为foo :: baz(k)进行访问。您必须在foo中明确定义baz(const bar&)才能通过限定名称访问它。
谢谢,希望对您有所帮助,但当然,我喜欢挑战:)。
- 3 回答
- 0 关注
- 419 浏览
添加回答
举报