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

Xeo*_*Xeo 32 c++ scope inline friend

在搜索到SO之后,一个问题告诉我,内联友元函数的词法范围是它定义的类,这意味着它可以访问例如typedef类中的s而不限定它们.但后来我想知道这种功能的实际范围是什么?海湾合作委员会至少拒绝我所有打电话的尝试.可以通过除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
  }
}
Run Code Online (Sandbox Code Playgroud)

导致这些错误:

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
Run Code Online (Sandbox Code Playgroud)

CB *_*ley 35

在类中声明friend具有非限定id的函数时,它会在最近的封闭命名空间作用域中命名一个函数.

如果先前未声明该函数,则friend声明不会使该函数在该范围内可见,以进行正常查找.它确实使声明的函数对依赖于参数的查找可见.

许多注释都强调了这一点,但最终的陈述在7.3.1.2/3(ISO/IEC 14882:2011)中:

首先在名称空间中声明的每个名称都是该名称空间的成员.如果friend非本地类中的声明首先声明一个类或函数,那么友元类或函数是最内层封闭命名空间的成员.在非命名查找(3.4.1)或限定查找(3.4.3)之前找不到朋友的名称,直到在该命名空间范围内提供匹配声明(在授予友谊的类定义之前或之后).如果调用了友元函数,则可以通过名称查找找到其名称,该名称查找考虑名称空间中的函数和与函数参数类型相关联的类(3.4.2).如果friend声明中的名称既不是限定名也不是模板标识,并且声明是函数或详细类型说明符,则确定实体是否先前已声明的查找不应考虑最内层封闭命名空间之外的任何范围.

  • 完美,它甚至是 C++03 标准中的同一段。这句话很隐蔽……谢谢! (2认同)

小智 6

《C++ 编程语言第三版 (Stroustrap)》:p279:

\n\n

I.“与成员声明一样,友元声明不会将名称引入封闭范围”

\n\n

二. “友元类必须事先在封闭范围中声明,或在非类范围中定义,\n立即封闭声明它为友元的类”

\n\n

三.“友元函数可以像友元类一样显式声明,也可以通过其参数类型 (\xc2\xa78.2.6) 找到它,就好像它是在立即包含其类的非类\n作用域中声明的一样。”

\n\n

四.“因此,友元函数应该在封闭范围内显式声明,或者采用其类的参数。如果没有,则无法调用友元。例如:”

\n\n
//no f() here\nvoid g();\nclass X{\n    friend void f();          //useless\n    friend void g();          //can be found because it is declared outside of class scope\n    friend void h(const X&);  //can be found because the arguments access class members\n};\n\nvoid f() { }                 //enemy of X :)\n
Run Code Online (Sandbox Code Playgroud)\n\n

但就您而言,还有更多与名称空间有关的内容,因为如果您在 foo 中放置正确的声明,例如:

\n\n
namespace foo{\n  struct bar{\n    friend void baz(const &bar){};\n    void call_friend();\n  }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

不编译。但是,如果您在 foo 之外声明它,那么它就像一个魅力。现在考虑一下,事实上,全局、局部、结构和类实际上都是命名空间。现在得出的结论是 是baz(const &)在全局范围内隐式定义的。

\n\n

这编译:

\n\n
namespace foo{\n  struct bar{\n    friend void baz(const bar&){};\n    void call_friend();\n  };\n}\n\nint main(){\n    foo::bar k;\n    baz(k);\n    return 0;\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

因此,存在两个问题:

\n\n
    \n
  1. 友元声明不会在封闭范围内引入名称,除非 IV。因此,原始程序无法找到 baz(),因为它没有被正确声明。
  2. \n
  3. 如果是 IV ,即 ADL ,那么该函数可以在 foo 中找到,但由于 ADL 的原因不能作为 foo::baz(k) 访问。您必须在 foo 中显式定义 baz(const bar&) 才能通过限定名称访问它。
  4. \n
\n\n

谢谢,希望它有帮助,但当然,我喜欢这个挑战:)。

\n