signed Referenzen auf unsigned unmöglich?
-
Danke. Da war mein bisheriges Verständnis von Referenzen wohl nicht richtig.
-
Karl R schrieb:
Ich bin gerade etwas überrascht, dass die implizite Konvertierung zwischen signed und unsigned ihre Grenzen bei Referenzen hat:
void set_to_0(int& i){i=0;} int main() { unsigned int i; set_to_0(i); }Wie kann ich sowas machen?
Gar nicht. Die Funktion erwartet einen int, Du übergibst einen unsigned int. Hier findet eine implizite Konvertierung statt. Das Ergebnis dieser Konvertierung ist ein temporärer int. Nicht-Const-Referenzen binden aber keine Temporären Objekte. Mit einem sehr ähnlichen Beispiel wird auch immer erklärt, warum es eine gute Idee ist, Nicht-Const-Referenzen keine temporären Objekte binden zu lassen; denn wenn es anders wäre, würde nur der temporäre Int verändert und das i hat hätte dann immer noch denselben Wert.
Mit dem Reinterpretieren muss man ganz super doll vorsichtig sein. Du sagst dem Compiler "Hey, ich weiß, was ich tue, also lass mich!" und erlaubst Dir, das Typsystem zu umgehen. Wenn Du allerdings nicht weißt, was Du tust, kann es ganz schön nach hinten losgehen.
Gruß,
SP
-
Sebastian Pizer schrieb:
Die Funktion erwartet einen int, Du übergibst einen unsigned int. Hier findet eine implizite Konvertierung statt. Das Ergebnis dieser Konvertierung ist ein temporärer int. Nicht-Const-Referenzen binden aber keine Temporären Objekte. Mit einem sehr ähnlichen Beispiel wird auch immer erklärt, warum es eine gute Idee ist, Nicht-Const-Referenzen keine temporären Objekte binden zu lassen; denn wenn es anders wäre, würde nur der temporäre Int verändert und das i hat hätte dann immer noch denselben Wert.
Das wäre richtiger, wenn du "temporäres Objekt" durch rvalue ersetzt. Schließlich erzeugt auch die normale arithmetische Konvertierung unsigned->int kein temporäres Objekt sondern eben nur den Wert an sich.
Darin liegt ja gerade der Sinn der Unterscheidung zwischen l- und rvalue (die aber nur bei Skalaren so funktioniert), ein lvalue ist ein Ausdruck der sich auf das Objekt, d.h. den Speicherbereich bezieht, während das rvalue sich den reinen Wert (=Inhalt oder Zustand eines ggf. gedachten Objektes) bezieht.Die Initialierung einer nicht-const Referenz des Typs int erfordert als Initialisierer eine Ausdruck, der ein int-Objekt repräsentiert (=int-lvalue) oder in einen solchen konvertierbar ist. Ein solche Konvertierung existiert nicht im Falle unsigned, also ist die Initialisierung der Funktionsparamters nicht möglich.
-
Die Unterscheidung zwischen "Wert" und "temporäres Objekt" in diesem Kontext ist meiner Meinung nach Haarspalterei. Ich habe hier eigentlich absichtlich den Begriff "Rvalue" vermieden.
camper schrieb:
Das wäre richtiger, wenn du "temporäres Objekt" durch rvalue ersetzt. Schließlich erzeugt auch die normale arithmetische Konvertierung unsigned->int kein temporäres Objekt sondern eben nur den Wert an sich.
...was man aber nicht wirklich voneinander unterscheiden kann. Warum sich dann also Sonderregeln für Skalare merken?
Ist es immer noch ein Wert in C++0x?
unsigned foo = 23; int && xxx = foo; // :-)Gruß,
SP
-
Sebastian Pizer schrieb:
Die Unterscheidung zwischen "Wert" und "temporäres Objekt" in diesem Kontext ist meiner Meinung nach Haarspalterei.
Vielleicht. Es kann auch auf ein Verständnisproblem hindeutet - allemal ist es jedenfalls missverständlich.
Sebastian Pizer schrieb:
...was man aber nicht wirklich voneinander unterscheiden kann.
Dem kann ich mich nicht anschließen. Ein temporäres Objekt hat eine Adresse, ist Speicher.
Sebastian Pizer schrieb:
Warum sich dann also Sonderregeln für Skalare merken?
Weil es an irgendeiner Stelle auch mal um Inhalte gehen muss?ohne Sie kein
Ist es immer noch ein Wert in C++0x?
unsigned foo = 23; int && xxx = foo; // :-)aber ja! (wenn xxx dann benutzt wird).
Letztlich ist der Begriff "temporäres Objekt" äußerst unglücklich. Denn "temporär" ist in dem Zusammenhang gerade keine Eigenschaft des Objektes, sondern eine Beziehung zwischen dem Objekt und dem Ausdruck, durch das es erzeugt wird. Andernfalls ist nicht begreifen, wieso z.B.
struct foo { foo& self() { return *this; } }; foo& x = foo(); // das illformed ist, foo& y = foo().self(); // das aber nichtVielleicht bin auch zu pedantisch; jedenfalls hat mich dieser scheinbare Widerspruch lange verwirrt.
-
camper schrieb:
Sebastian Pizer schrieb:
...was man aber nicht wirklich voneinander unterscheiden kann.
Dem kann ich mich nicht anschließen. Ein temporäres Objekt hat eine Adresse, ist Speicher.
Ja und? Mein Punkt war, dass Du kein C++ Programm schreiben kannst, welches den Unterschied feststellen könnte. Oder täusche ich mich da jetzt?
Gruß,
SP
-
Sebastian Pizer schrieb:
camper schrieb:
Sebastian Pizer schrieb:
...was man aber nicht wirklich voneinander unterscheiden kann.
Dem kann ich mich nicht anschließen. Ein temporäres Objekt hat eine Adresse, ist Speicher.
Ja und? Mein Punkt war, dass Du kein C++ Programm schreiben kannst, welches den Unterschied feststellen könnte. Oder täusche ich mich da jetzt?
Welchen Unterschied? Das es sich um verschiedene Konzepte handelt? Das wäre ungefähr so sinnvoll, wie den Unterschied zwischen Klassen und Objekten per Programm feststellen zu wollen.
-
camper schrieb:
Welchen Unterschied? Das es sich um verschiedene Konzepte handelt? Das wäre ungefähr so sinnvoll, wie den Unterschied zwischen Klassen und Objekten per Programm feststellen zu wollen.
Na, übertreibe mal nicht. Du kannst diesen "Wert" wie ein namenloses Objekt behandeln. Der Standard sagt, Rvalue-Ausdrücke für Skalare referenzieren keine Objekte. Na und? Für den Programmierer macht das keinen sichtbaren Unterschied. Ob's nun ein "Wert" oder ein "namenloses Objekt" ist ...
Gruß,
SP
-
Lustig, wenn zwei Experten sich "streiten"... und der Thread-Ersteller wahrscheinlich nur Bahnhof versteht -)
-
foo &f = foo().self()
...
das ist doch auch eine referenz auf eine temporäre variable.
ob jetzt foo oder *this, es ist ungültig
-
camper schrieb:
...ein lvalue ist ein Ausdruck der sich auf das Objekt, d.h. den Speicherbereich bezieht, während das rvalue sich den reinen Wert (=Inhalt oder Zustand eines ggf. gedachten Objektes) bezieht...

Das ist das erste Mal, dass ich einen halbwegs konsistenten Eindruck davon habe, was mit R-/Lvalue gemeint ist.
(ansonsten habe ich eher technische oder "ist wenn"-Erklärungen gelesen, die ich alle wenig befriedigend/hilfreich fand - vielleicht auch nicht ausreichend verstand)Danke,
Simon2.
-
Simon2 schrieb:
Das ist das erste Mal, dass ich einen halbwegs konsistenten Eindruck davon habe, was mit R-/Lvalue gemeint ist.
(ansonsten habe ich eher technische oder "ist wenn"-Erklärungen gelesen, die ich alle wenig befriedigend/hilfreich fand - vielleicht auch nicht ausreichend verstand)Hast du Stroustrups Buch nie gelesen? - Dort steht das ziemlich genau auch so drinn.

-
drakon schrieb:
Hast du Stroustrups Buch nie gelesen? - Dort steht das ziemlich genau auch so drinn.

Wo denn? Welche Version hast Du denn? Ich habe hier die "4. Auflage" (deutsche Übersetzung der Special Edition) liegen. Im Index ist zwar "Lvalue" zu finden, aber nicht "Rvalue". Beim Überfliegen des Inhaltsverzeichnisses finde ich Abschnitt "10.4.10 Temporäre Objekte":
Temporäre Objekte sind meistens das Ergebnis arithmetischer Ausdrücke. Zum Beispiel muß bei der Auswertung des Ausdrucks x*y+z das Zwischenergebnis x*y irgendwo stehen. Steht keine Performanz zur Diskussion (§11.6), muß sich der Programmierer selten um temporäre Objekte kümmern. Trotzdem kommt es vor (§11.6, §22.4.7) [...]
Gruß,
SP
-
Sebastian Pizer schrieb:
drakon schrieb:
Hast du Stroustrups Buch nie gelesen? - Dort steht das ziemlich genau auch so drinn.

Wo denn? Welche Version hast Du denn? Ich habe hier die "4. Auflage" (deutsche Übersetzung der Special Edition) liegen. Im Index ist zwar "Lvalue" zu finden, aber nicht "Rvalue".
Hmm. Ich hatte es im Kopf, dass es da erklärt wird, aber dem ist tatsächlich nicht so.. Demfall habe ich dann halt Rvalue genau so vorgestellt, wie camper es beschrieben hat und gemeint, dass es da so erklärt wurde.. :p