内联朋友function的范围是什么?
经过search后,有一个问题告诉我,内联函数的词法范围就是它所定义的类,这意味着它可以访问类中的typedef
,而不需要限制它们。 但是我想知道这个function的实际范围是什么? 海湾合作委员会至less拒绝了我所有的企图。 像例子中的函数可以通过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
当你在一个类中声明一个带有非限定标识的friend
函数时,它会在最近的封闭名字空间作用域中命名一个函数。
如果该函数以前没有被声明过,那么friend
声明不会使该函数在该范围内可见,用于正常查找。 它确实使声明的函数对依赖于参数的查找可见。
在许多说明中都强调了这一点,但是确定性声明在ISO / IEC 14882:2011的7.3.1.2/3中:
名称空间中首先声明的每个名称都是该名称空间的成员。 如果非本地类中的
friend
声明首先声明了一个类或函数,那么朋友类或函数是最内层的名字空间的成员。 直到在该名称空间范围内 (在授予友谊的类定义之前或之后)提供匹配声明之前,通过无限制查找(3.4.1)或合格查找(3.4.3)才能find该朋友的名字 。 如果调用好友函数,则可以通过名称查找find其名称,该名称查找考虑了与函数参数types(3.4.2)相关的名称空间和类的函数。 如果friend
声明中的名称既不是限定名也不是模板标识 ,并且声明是函数或详细types说明符 ,则确定实体是否先前已声明的查找不应考虑最内层封闭名称空间之外的任何作用域。
“C ++编程语言第三版(Stroustrap)”:p279:
I.“就像一个成员声明一样,一个朋友声明不会把一个名字引入一个封闭的范围”
II。 “朋友类必须事先在封闭范围内声明,或者在非类范围中定义,并立即包含声明它为朋友的类”
III。 “朋友函数可以像朋友类一样显式声明,也可以通过其参数types(第8.2.6节)find,好像它是在非类作用域中直接声明的类一样。
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中find,但不能作为foo :: baz(k)被访问,这是由于ADL引起的。 你将不得不明确地在foo中定义baz(const bar&)来通过限定的名字来访问它。
谢谢,希望它有帮助,但当然,我喜欢这个挑战:)。
有趣!
编译器似乎不知道它属于什么范围(说实话,没有线索),因此没有放在任何范围内。 一些标准的挖掘我想。
注意:如果你明确地将一个声明添加到一个特定的范围,那么它开始按预期工作。
namespace foo { void baz(); // declare it here and now it works in foo namespace etc. struct bar { friend void baz(){} void call_friend(); }; }
挖掘标准,我发现:
11.3朋友[class.friend]
第6段
一个函数可以定义在一个类的友元声明中,当且仅当该类是一个非本地类(9.8), 该函数名是不合格的,并且该函数具有命名空间范围 。
[ Example: class M { friend void f() { } // definition of global f, a friend of M, // not the definition of a member function }; — end example ]
第7段
这样的function隐式内联。 在一个类中定义的朋友函数在它定义的类的(词法)范围内 。 在类外定义的朋友函数不是(3.4.1)。
注意:
作为一个朋友,没有参数的独立function不是很有用。 因为它没有任何对象利用它的友谊(我想文件范围静态存储持续时间的对象)。
在这个例子中,
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 } }
-
foo::baz()
不可访问,因为名称baz
在名称空间foo
作用域中不可见。 如果我没有记错的话(§3.4 / 2)在这里适用。 -
foo::bar::baz()
是不可访问的,因为朋友不是类的成员,并且内联的朋友函数的作用域是它们的定义存在的名称空间或类,所以你不能访问它们。
如果在foo
放入baz()
的声明,那么函数baz
的名字将在foo
可见,定义将在bar
的嵌套范围内查找。
namespace foo{ void baz(); // declaration at namespace scope struct bar{ friend void baz(){} }; void call_friend() { baz(); // ok } } int main() { foo::baz(); // ok, bar will be looked up in the nested scope of foo::bar. }
我觉得你是在混淆friend
和private
。 通过声明一个friend
function,你授予它访问你的私人成员,而不是其他function访问它。 无论如何,结构的任何成员函数都可以被任何对象访问,因为struct
成员默认是公共的。
然而,在你的情况下baz
是不可访问的,因为通过friend void baz(){}
你没有真正的声明函数baz
,你只是说,这是一个friend
函数。 你可以删除friend
关键字,它会解决所有的问题。