ostream Verkettung, Reihenfolge der Ausgabe

8

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:

%Vor%

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<< ?

ketten kann?     
LowTechGeek 19.01.2012, 18:22
quelle

5 Antworten

5

Das Verhalten Ihres Codes ist unspezifiziert gemäß C ++ Standard.

Erklärung

Folgendes (Ich entfernte std::endl zur Vereinfachung)

%Vor%

entspricht dem:

%Vor%

ist ein Funktionsaufruf, der zwei Argumente übergibt:

  • Das erste Argument lautet: operator<<(std::cout, "Hello, World!")
  • Zweites Argument ist: 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).

Warum hexadezimale Ausgabe?

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%     
Nawaz 19.01.2012, 18:32
quelle
2

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.

>     
Joachim Isaksson 19.01.2012 18:30
quelle
1

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.

    
bames53 19.01.2012 18:34
quelle
1

Dies würde funktionieren, um print mit << zu kombinieren und die Reihenfolge zu kontrollieren:

%Vor%

Oder, wenn Sie eine Funktion wollen, die mit << aufgerufen wird, sehen Sie sich Joachims Antwort an.

    
Ben Voigt 19.01.2012 18:36
quelle
1

Hexadezimale Ausgabe

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.

Evaluierungsauftrag

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)

%Vor%

LIVE-BEISPIEL

    
xskxzr 05.03.2018 12:14
quelle

Tags und Links