Gegeben GMans köstlich böse auto_cast
Dienstprogramm-Funktion zusammengebraut hier , ich habe versucht herauszufinden, warum es nicht für mich kompiliert, wenn ich auto_cast
von einem rvalue (auf MSVC 10.0) versuche.
Hier ist der Code, den ich verwende:
%Vor%Nach bestem Wissen habe ich versucht, den C ++ 0x-Referenz-Kollabierungsregeln und den Schablonen-Argumentableitungsregeln zu folgen, die umrissen wurden hier , und soweit ich das beurteilen kann, sollte der oben angegebene Code funktionieren.
Erinnern Sie sich daran, dass es in pre-0x C ++ nicht erlaubt ist, einen Verweis auf eine Referenz zu nehmen: so etwas wie A & amp; &Ampere; verursacht einen Kompilierungsfehler. Im Gegensatz dazu führt C ++ 0x die folgenden kollabierenden Referenzregeln ein:
- A & amp; &Ampere; wird A & amp;
- A & amp; & amp; & amp; wird A & amp;
- A & amp; & amp; &Ampere; wird A & amp;
- A & amp; & amp; & amp; & amp; wird A & amp; & amp;
Die zweite Regel ist eine spezielle Regel für die Ableitung von Matrizenargumenten für Funktionsschablonen, die ein Argument mit einem Verweis auf ein Vorlagenargument verwenden:
%Vor%Hier gelten die folgenden Regeln:
- Wenn foo für einen lvalue vom Typ A aufgerufen wird, dann wird T in A & amp; und daher wird der Argumenttyp durch die oben genannten Kollabierungsreferenzregeln effektiv zu A & amp ;.
- Wenn foo für einen rvalue vom Typ A aufgerufen wird, dann wird T in A aufgelöst, und daher wird der Argumenttyp zu A & amp; & amp;.
Wenn ich nun den Aufruf von auto_cast( 5.0f )
mit der Maus drücke, zeigt der Tooltip den Rückgabewert korrekt als auto_cast_wrapper<float>
an. Dies bedeutet, dass der Compiler die Regel 2 korrekt befolgt hat:
Wenn foo für einen rvalue vom Typ A aufgerufen wird, dann wird T in A aufgelöst.
Da wir also ein auto_cast_wrapper<float>
haben, sollte der Konstruktor instanziieren, um ein float&&
zu nehmen. Aber die Fehlermeldung scheint zu implizieren, dass es eine float
nach Wert instanziiert.
Hier ist die vollständige Fehlermeldung, die wieder zeigt, dass T = korrekt schwebt, aber die T & amp; & amp; Parameter wird T?
%Vor%
Irgendwelche Gedanken?
Entschuldigung für das Posten von nicht getestetem Code. :)
DeadMG ist richtig, dass das Argument ebenfalls weitergeleitet werden sollte. Ich glaube, die Warnung ist falsch und die MSVC hat einen Fehler. Berücksichtigen Sie den Anruf:
%Vor% T()
wird bis zum Ende des vollständigen Ausdrucks leben, was bedeutet, dass die Funktion auto_cast
, der Konstruktor auto_cast_wrapper
und die benutzerdefinierte Konvertierung alle auf ein noch gültiges Objekt verweisen.
(Da der Wrapper nichts anderes tun kann als konvertieren oder zerstören, kann er den Wert, der in auto_cast
übergeben wurde, nicht überleben.)
Ich repariere vielleicht, um das Mitglied zu einem T
zu machen. Sie werden eine Kopie erstellen / verschieben, anstatt das ursprüngliche Objekt direkt zu übertragen. Aber vielleicht mit Compiler-Optimierung geht es weg.
Und nein, die Weiterleitung ist nicht überflüssig. Es verwaltet die Wertkategorie von dem, was wir automatisch konvertieren:
%Vor% Und wenn ich mich nicht irre, sollte der Konvertierungsoperator nicht (sicherlich nicht unbedingt) als const
markiert sein.
Der Grund, warum es nicht kompiliert, ist der gleiche Grund, warum dies nicht kompiliert:
%Vor% As a
ist selbst ein Lvalue und kann nicht an b
gebunden werden. Im auto_cast_wrapper
-Konstruktor hätten wir std::forward<T>
erneut für das Argument verwenden müssen, um dies zu beheben. Beachten Sie, dass wir im obigen Beispiel einfach std::move(a)
verwenden können, aber dies würde nicht den generischen Code abdecken, der auch mit lvalues arbeiten sollte. Also wird der auto_cast_wrapper
-Konstruktor nun zu:
Leider scheint dies jetzt undefiniertes Verhalten zu zeigen. Ich bekomme folgende Warnung:
warning C4413: 'auto_cast_wrapper :: mX': Referenzelement wird mit einem temporären initialisiert, das nach dem Beenden des Konstruktors nicht mehr existiert
Es scheint, dass das Literal den Gültigkeitsbereich verlässt, bevor der Konvertierungsoperator ausgelöst werden kann. Obwohl dies nur ein Compilerfehler mit MSVC 10.0 sein könnte. Aus GMans Antwort sollte die Lebenszeit eines Temporären bis dahin leben das Ende des vollständigen Ausdrucks.
Tags und Links c++ c++11 rvalue-reference