天儿真好!
我对在C ++中使用friend
有疑问。请考虑以下代码:
#include <ostream>
struct F {
};
struct N {
friend std::ostream& operator<< (std::ostream&, const N&);
friend std::ostream& operator<< (std::ostream&, const F&);
};
void foo(std::ostream &out) {
F bar;
out << bar;
}
我的理解始终是,friend
与static
类似,具有friend
函数可以访问类的私有部分的附加属性。在这个假设下,代码应该编译,因为operator<<
有一个ostream&
和一个(const)F&
。
g ++ 4.0似乎与我分享了我的想法,因为它接受了这个代码。然而,更新的g ++ 4.5(.2)拒绝带有消息的代码:
ns.cc: In function 'void foo(std::ostream&)':
ns.cc:14:10: error: no match for 'operator<<' in 'out << bar'
是g ++ 4.5错了还是我(和g ++ 4.0)错了?
(将好友声明移到F
课程的解决方案没有帮助,因为operator<<
需要访问N
的私有部分。)
此致 斯蒂芬
答案 0 :(得分:5)
问题是,除非您提供内联实现,否则友元声明不会提供全局函数声明。
struct N {
friend void func1() { }
friend void func2();
friend void func3();
};
void func3();
func1(); /* OK */
func2(); /* not OK */
func3(); /* OK */
答案 1 :(得分:4)
您还必须在结构外部声明运算符。 gcc 4.4报告了相同的错误。
#include <ostream>
struct F {
};
struct N {
friend std::ostream& operator<< (std::ostream&, const N&);
friend std::ostream& operator<< (std::ostream&, const F&);
};
std::ostream& operator<< (std::ostream&, const N&);
std::ostream& operator<< (std::ostream&, const F&);
void foo(std::ostream &out) {
F bar;
out << bar;
}
答案 2 :(得分:0)
自从我看到问题以来,我一直在跋涉标准(FCD,n3242)
在 [class.friend] 中可以阅读:
6)当且仅当该类是非本地类(9.8),函数名称不合格且函数具有命名空间范围时,才能在类的友元声明中定义函数。
7)这样的功能是隐式内联的。在类中定义的友元函数位于定义它的类的(词法)范围内。在课外定义的朋友函数不是(3.4.1)。
9)朋友声明提名的名称应在包含朋友声明的类的范围内访问。
那么,这里会发生什么?
struct F {
};
struct N {
friend std::ostream& operator<< (std::ostream&, const F&);
};
朋友声明提名operator<<
的这个重载是N
的朋友。但是,这个重载尚未在词法范围(命名空间或类)中声明。另外,7
不适用,因为它未在N
内定义。
因此,在查找可应用于operator<<
的重载时:
void foo(std::ostream &out) {
F bar;
out << bar;
}
没有有效的过载(实际上,可能根本没有过载)。
您有两种解决方案:
7
:在朋友声明之后定义内联函数。9
:声明命名空间中的函数因为4
:
4)在朋友声明中首先声明的函数具有外部链接(3.5)。否则,该函数将保留其先前的链接(7.1.1)。
我建议将之前声明为friend
声明来控制其链接,但这很少有用。