I want to implement the <<operator to stream my class (let's say it's called Paragraph ). The Paragraph class has some personal data, for this reason I want the (stand-alone) operator <to be a friend. So, I suggest, for example, here on SO . friend , execute operator<< and everything will be fine.
But now I want to put Paragraph inside a namespace, say namespace foo . This is no longer working! If I write:
namespace foo { class Paragraph { public: explicit Paragraph(std::string const& init) :m_para(init) {} std::string const& to_str() const { return m_para; } private: friend std::ostream & operator<<(std::ostream &os, const Paragraph& p); std::string m_para; }; } // namespace foo
The compiler tells me that I became friends with foo::operator<< and not ::operator<< . Good, right. So, I will replace the friend line:
friend std::ostream & ::operator<<(std::ostream &os, const Paragraph& p);
but I get an error again (from GCC 5.4.0) telling me that ::operator<< not been declared. Ok, let it announce it. Will this work ?:
namespace foo { std::ostream & ::operator<<(std::ostream &os, const foo::Paragraph& p); class Paragraph { public: explicit Paragraph(std::string const& init) :m_para(init) {} std::string const& to_str() const { return m_para; } private: friend std::ostream & operator<<(std::ostream &os, const Paragraph& p); std::string m_para; }; } // namespace foo
No, he does not know about the paragraph when reading the declaration ::operator< . Ok, let forward-declare:
namespace foo { class Paragraph; std::ostream & ::operator<<(std::ostream &os, const foo::Paragraph& p); class Paragraph { /* actual definition here */ } } std::ostream & operator<<(std::ostream &os, const foo::Paragraph& p) { /* impl */ }
Bad luck. I get a weird error:
f.cpp:23:16: note: candidate: std::ostream& operator<<(std::ostream&, const foo::Paragraph&) std::ostream & operator<<(std::ostream &os, const foo::Paragraph& p) ^ f.cpp:11:15: note: candidate: std::ostream& operator<<(std::ostream&, const foo::Paragraph&) std::ostream& ::operator<<(std::ostream &os, const foo::Paragraph& p);
... and here I thought the global namespace and namespace :: is the same ... arent 'they? (sigh). It doesn't matter, release the declaration from the namespace:
class foo::Paragraph; std::ostream & operator<<(std::ostream &os, const foo::Paragraph& p); namespace foo { class Paragraph { /* actual definition here */ } } std::ostream & operator<<(std::ostream &os, const foo::Paragraph& p) { /* impl */ }
Still not good enough, now I get the error message "foo" has not been announced. (removes teeth) excellent! Be that way!
namespace foo { class Paragraph; } std::ostream & operator<<(std::ostream &os, const foo::Paragraph& p); namespace foo { class Paragraph { /* actual definition here */ } } std::ostream & operator<<(std::ostream &os, const foo::Paragraph& p) { /* impl */ }
so this, but no less, works. This is terrible! Of course, there must be some less sure way to do this ... right?
Note: Assume that operator<< cannot be embedded and must be defined separately.