为了账号安全,请及时绑定邮箱和手机立即绑定

内联好友功能的范围是什么?

内联好友功能的范围是什么?

C++
子衿沉夜 2019-09-24 16:42:21
在SO周围搜索之后,有一个问题告诉我,内联好友函数的词法范围是其定义的类,这意味着它可以访问typedef类中的,而无需对其进行限定。但是我想知道这样的功能的实际范围是什么?GCC至少拒绝了我所有的调用尝试。能否通过非ADL的方式调用示例中的函数(由于没有参数,在这里是不可能的)?感谢标准报价,因为我目前无法访问它的副本。以下代码namespace foo{  struct bar{    friend void baz(){}    void call_friend();  };}int main(){  foo::baz();           // can't access through enclosing scope of the class  foo::bar::baz();    // can't access through class scope}namespace foo{  void bar::call_friend(){    baz();    // can't access through member function  }}导致以下错误:prog.cpp: In function ‘int main()’:prog.cpp:9: error: ‘baz’ is not a member of ‘foo’prog.cpp:10: error: ‘baz’ is not a member of ‘foo::bar’prog.cpp: In member function ‘void foo::bar::call_friend()’:prog.cpp:15: error: ‘baz’ was not declared in this scope
查看完整描述

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,则用于确定该实体先前是否已声明的查找将不考虑最内层封闭名称空间之外的任何作用域。


查看完整回答
反对 回复 2019-09-24
?
qq_笑_17

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&)才能通过限定名称访问它。

谢谢,希望对您有所帮助,但当然,我喜欢挑战:)。


查看完整回答
反对 回复 2019-09-24
  • 3 回答
  • 0 关注
  • 397 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信