非限定的友元声明始终引用最小的封闭命名空间的成员.在命名空间中usr
声明类时,该类中的任何非限定的友元声明都引用其成员usr
.即你的朋友宣言被宣布usr::operator <<
为朋友.
::operator <<
在这种情况下,全局仍然是非朋友,这就是当您尝试访问usr::A
来自的私有成员时出现错误的原因::operator <<
.
如果你想要这个,你必须要么
成为你operator <<
的成员usr
,或
operator <<
通过使用限定名称确保friend声明明确引用global ::operator <<
(::operator <<
在尝试通过其限定名称引用它之前,还需要引入).
我会建议第一种方法.如果您的类A
是命名空间的成员usr
,那么声明所有处理A
成为成员的函数也是一个好主意usr
.这将帮助您避免许多与参数相关的查找(ADL)问题.
但是如果由于某种原因你需要你operator <<
仍然是全局命名空间的成员,那么这里是你必须跳过来使它编译的箍(组合成一个单独的翻译单元)
// Pre-declare `usr::A` to enable pre-declaration of our `::operator <<` namespace usr { class A; } // Pre-declare our `::operator <<` std::ostream& operator<<(std::ostream& os, const usr::A& a); namespace usr { class A { private: int m_x; public: A(int x); friend std::ostream& ::operator<<(std::ostream& os, const usr::A& a); // Friend declaration uses qualified name - it explicitly // refers to `::operator <<` declared above }; } usr::A::A(int x) : m_x(x) {} std::ostream& operator<<(std::ostream& os, const usr::A& a) { os << a.m_x; return os; } int main() { usr::A a(4); std::cout << a << std::endl; }