Ich möchte einen Operator < < für das Streaming meiner Klasse implementieren (sagen wir es Paragraph
). Klasse Paragraph
hat einige private Daten, aus diesem Grund möchte ich den (freistehenden) Operator < < Funktion ein Freund sein. Also tue ich wie vorgeschlagen, z. B. here on SO. friend
Anweisung, implementieren Sie die operator<<
und alles ist gut.Muss ich mich wirklich für einen Freund-Operator << für eine Klasse in einem Namespace bücken?
Aber jetzt möchte ich Paragraph in einen Namensraum, sagen namespace foo
. Es funktioniert nicht mehr! Wenn ich schreibe:
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
Der Compiler sagt mir, ich habe foo::operator<<
befreundeten, nicht ::operator<<
. OK Fair genug. Also ersetze ich die Freundin Linie mit:
friend std::ostream & ::operator<<(std::ostream &os, const Paragraph& p);
aber ich erhalte eine Fehlermeldung erneut (von GCC 5.4.0), mir zu sagen, die ::operator<<
hat nicht erklärt worden ist. Ok, lass es uns dann erklären. Wird diese Arbeit ?:
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
Nein, es weiß nicht, über Absatz, wenn die Deklaration von ::operator<
lesen. Ok, lass uns vorwärts deklarieren:
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 */ }
kein Glück. Ich erhalte die seltsamen Fehler:
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);
... und hier war ich der globale Namensraum zu denken und die :: Namespace sind die gleiche Sache ... Arent‘sie? (Seufzer). Egal, lassen Sie uns die Erklärung bewegen aus dem Namensraum:
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 */ }
noch nicht gut genug, jetzt bekomme ich die Fehlermeldung „‚foo‘wurde nicht deklariert“. (Zähneknirschen) gut! Sei auch so!
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 das, aber nicht weniger als das, funktioniert. Das ist schrecklich! Sicherlich muss es eine Art weniger wortreichen Weg geben, es zu tun ... richtig?
Hinweis: Angenommen, die operator<<
kann nicht inline sein und muss separat definiert werden.
Ihr erster Satz traf den Nagel auf den Kopf. Oder vielleicht sollte ich meinen Kopf sagen. – einpoklum
@einpoklum Darüber hinaus ist dies die einzige Lösung, die garantiert, dass die Namenssuche erfolgreich ist. ':: operator <<' würde in einigen Kontexten nicht gefunden werden, da es nicht Teil des ADL-Lookup-Sets ist. –