Ich habe eine Funktion, die einen ostream
Verweis als Argument verwendet, einige Daten in den Stream schreibt und dann einen Verweis auf denselben Stream zurückgibt, so:
Die Ausgabe dieses Codes lautet:
%Vor%Wenn ich die Verkettungsausdrücke jedoch in zwei Anweisungen aufteile, so
%Vor%dann bekomme ich zumindest die richtige Reihenfolge in der Ausgabe, bekomme aber trotzdem einen Hex-Wert:
%Vor% Ich würde gerne verstehen, was hier vor sich geht. Hat eine normale Funktion Vorrang vor operator<<
, und deshalb kehrt sich die Reihenfolge der Ausgabe um? Wie schreibt man eine Funktion, die Daten in ostream
einfügt, aber auch mit operator<<
?
Das Verhalten Ihres Codes ist unspezifiziert gemäß C ++ Standard.
Folgendes (Ich entfernte std::endl
zur Vereinfachung)
entspricht dem:
%Vor%ist ein Funktionsaufruf, der zwei Argumente übergibt:
operator<<(std::cout, "Hello, World!")
print(std::cout)
Jetzt gibt der Standard nicht die Reihenfolge an, in der Argumente ausgewertet werden. Es ist nicht spezifiziert . Aber Ihr Compiler scheint das zweite Argument zuerst auszuwerten, deshalb druckt er "Wie geht es Ihnen?" und bewertet das zweite Argument mit einem Wert vom Typ std::ostream&
, der dann an den Aufruf übergeben wird oben gezeigt (dieser Wert ist das Objekt std::cout
selbst).
Sie erhalten eine hexadezimale Ausgabe, weil das zweite Argument als std::cout
ausgewertet wird, das als hexadezimale Zahl ausgegeben wird, weil std::cout
implizit in den Zeigerwert void*
type konvertiert, weshalb es als hexadezimale Zahl ausgegeben wird.
Versuchen Sie Folgendes:
%Vor%Es wird der gleiche Wert für beide ausgegeben. In diesem Beispiel gibt ideone Folgendes aus:
%Vor% Beachten Sie auch, dass ich die explizite -Ausführung nicht verwendet habe; Stattdessen wird std::cout
implizit in einen Zeigertyp umgewandelt.
Ich hoffe, das hilft.
Was ist der richtige Weg, um eine Funktion zu schreiben, die Daten in einen Ostream einfügt, die aber auch mit dem Operator & lt;
Wann kommt es darauf an, was Sie mit Verkettung meinen? Offensichtlich würde Folgendes nicht funktionieren (wie oben erklärt):
%Vor% Egal wie Sie print()
schreiben.
Das ist jedoch gut definiert:
%Vor%Der Grund ist, dass Ihre print () -Funktion vor dem Rest der Anweisung ausgewertet wird und einen Verweis auf cout zurückgibt, der dann tatsächlich als Zeiger gedruckt wird (cout & lt; & lt; cout). Diese Reihenfolge der Auswertung ist eigentlich nicht spezifiziertes Verhalten, scheint aber bei Ihrem Compiler der Fall zu sein.
Wie bei der Definition einer streambewussten "Funktion", die tatsächlich ein Verhalten mit derselben Funktionalität definiert, würde dies funktionieren;
%Vor%Siehe auch diese Antwort , um ein wenig detaillierter zu erfahren, was "nicht spezifiziert" in diesem Fall bedeutet.
> In Ihrer Anweisung std::cout << "Hello, world!" << print( std::cout ) << std::endl
ist nicht definiert, ob std::cout << "Hello, world!"
vor oder nach print( std::cout )
passiert. Deshalb ist die Reihenfolge möglicherweise nicht das, was Sie erwarten.
Der hexadezimale Wert kommt von der Tatsache, dass Sie auch std::cout << std::cout
( print
gibt std::cout
zurück, das in die <<
-Kette eingegeben wird). Die rechte std::cout
wird in eine void *
konvertiert und in die Ausgabe ausgegeben.
Vor C ++ 11 hat die Klasse std::ostream
eine Konvertierungsfunktion in void*
. Da Ihre Funktion print
std::ostream&
zurückgibt, wird bei der Auswertung von std::cout << print(...)
der zurückgegebene std::ostream
lvalue implizit in void*
konvertiert und dann als Zeigerwert ausgegeben. Deshalb gibt es eine hexadezimale Ausgabe.
Seit C ++ 11 wird diese Konvertierungsfunktion durch eine explizite Konvertierungsfunktion ersetzt to bool
, also versucht, ein std::ostream
-Objekt auszugeben, wird schlecht gebildet.
Vor C ++ 17 wird der überladene Operator als Funktionsaufruf zum Analysieren der Bewertungsreihenfolge betrachtet, und die Bewertungsreihenfolge verschiedener Argumente eines Funktionsaufrufs ist nicht spezifiziert. Es ist also nicht verwunderlich, dass die Funktion print
zuerst ausgewertet wird, was dazu führt, dass How are you?
zuerst ausgegeben wird.
Seit C ++ 17 ist die Auswertungsreihenfolge der Operanden des Operators <<
streng von links nach rechts, und die Operanden des überladenen Operators teilen sich die gleiche Bewertungsreihenfolge wie die des eingebauten Operators (siehe weitere Details hier ). Ihr Programm erhält also immer die Ausgabe (nehmen wir an, dass print
etwas zurückgibt, das ausgegeben werden kann)