In einigen Sprachen wie Ruby gibt es eine phantastische Syntax zum Erstellen der formatierten Ausgabe als ein "Einzeiler" zum Teil, weil dies häufig in Ruby-Anwendungen benötigt wird.Welche schlimmen Dinge würden passieren, wenn `std :: ostringstream` einen `operator <<` hat, der `std :: ostringstream &` zurückgibt?
Es wird auch häufig in einigen C++ - Anwendungen benötigt. Hier einige Beispiel-Code:
if (num_doggies > num_biscuits) {
std::ostringstream ss;
ss << "There are " << num_doggies" << " puppy dogs and only " << num_biscuits << " biscuits!";
log_warn(ss.str());
this->negotiate_biscuit_reduction();
}
Einige Open-Source-C++ 98 Projekte eine Abhilfe, die wie folgt aussieht:
struct string_formatter {
std::ostringstream ss;
template <typename T>
string_formatter & operator << (const T & t) {
ss << t;
return *this;
}
operator std::string() const {
return ss.str();
}
};
Damit sie so etwas schreiben können:
if (num_doggies > num_biscuits) {
log_warn(string_formatter{} << "There are " << num_doggies" << " puppy dogs and only " << num_biscuits << " biscuits!");
this->negotiate_biscuit_reduction();
}
drei Zeilen in eine Zeile umwandeln.
Allerdings sieht die string_formatter
Klasse aus Code-Review-Sicht, vor allem aufgrund dieser impliziten Konvertierung ziemlich böse. Implizite Konvertierungen werden normalerweise als ziemlich böse angesehen, und sie sind böser, wenn sie in gängige oder primitive Typen konvertiert werden. wie int
oder std::string
.
In C++ 11 können wir es leicht ändern:
operator std::string() && {
return ss.str();
}
Nun ist die Umwandlung wird nur ausgelöst, wenn die string_formatter
eine r-Wert Referenz. So ist es weniger wahrscheinlich zu lösen, aber es ist auch komplizierter. Ist es eigentlich weniger böse? Debattierbar.
Erwähnenswert: andere haben noch aufwändigere Hacks weg zu bekommen diese ohne string_formatter
Shim zu arbeiten: https://codereview.stackexchange.com/questions/6094/a-version-of-operator-that-returns-ostringstream-instead-of-ostream
keine impliziten Konvertierungen hier, aber wir sind Betreiber auf Standard-Bibliothekstypen zu überlasten, die in der Regel eine Nein, nein.
Lassen Sie uns ein wenig zurück. Warum kann ich nicht Kompromisse machen und dies tun? Es ist zumindest ein wenig kompakter:
if (num_doggies > num_biscuits) {
std::ostringstream ss;
log_warn((ss << "There are " << num_doggies" << " puppy dogs and only " << num_biscuits << " biscuits!").str());
this->negotiate_biscuit_reduction();
}
Es stellt sich heraus, dass dies nicht kompilieren, weil std::ostringstream::operator <<
kehrt std::ostream &
und nicht std::ostringstream &
. Zu der Zeit, die alle <<
aufgelöst haben, haben wir nur eine ostream &
, so dass wir .str()
nicht verwenden können.
Meine Frage ist, warum ist das der Fall?
Warum nicht std::ostringstream::operator <<
zurückgeben std::ostringstream &
?Ist es:
- Unerwünschte aus technischen oder sicherheitstechnischen Gründen
- unnötige Schwierigkeiten für Standardbibliothek Implementierer
- Vermächtnis Hinzufügen - es war immer so und es ändert sich jetzt vielleicht Code brechen. (Aber welcher Code würde genau dadurch gebrochen werden?
std::ostringstream &
kann aufgrund einer Vererbungsbeziehung durch eine Standardkonvertierung instd::ostream &
umgewandelt werden?) - Obscurity - niemand kümmert sich!
Hinweis: Ich kenne verschiedene Möglichkeiten, string_formatter
und Logger-Klassen zu entwerfen. Ich bin speziell interessiert, ob es Design-Gründe in der Standard-Bibliothek gibt, die es viel besser für std::ostringstream
machen, std::ostream &
zurückzugeben.
Sie können ein '.str()' auf 'string_formatter' triviale Weise hinzufügen, nicht wahr? –
@ T.C. Ja, aber das ist nicht wirklich der Punkt, ich bin mehr interessiert, wenn es einen guten Grund gibt, verstehe ich nicht, warum 'std :: ostringstream' 'std :: ostream &' –
zurückgeben muss, weil es keinen Operator << in ostringstream gibt ? Es verwendet grundlegende ostream durch Magie der Vererbung. –