Was ist der beste Weg, um eine Rvalue-Referenz entweder an ein gegebenes Objekt oder eine temporäre Kopie davon zu binden?Stil beim Binden eines Verweises auf Objekt oder Dummy
A &&var_or_dummy = modify? static_cast<A&&>(my_A)
: static_cast<A&&>(static_cast<A>(my_A));
(Dieser Code funktioniert nicht auf meinem letzten GCC 4.6 ... Ich erinnere mich, es vor der Arbeit, aber jetzt ist es gibt immer eine Kopie.)
In der ersten Zeile, die static_cast
verwandelt my_A
von einer Lvalue zu einem xvalue. (C++ 0x §5.2.9/1-3) Die innere static_cast
in der zweiten Zeile führt Lvalue-to-rvalue-Konvertierung, und die äußere erhält einen xvalue von diesem prvalue.
Dies scheint unterstützt zu werden, da die benannte Referenz bedingt an die temporäre nach §12.2/5 gebunden ist. Derselbe Trick funktioniert auf die gleiche Weise in C++ 03 mit einer const
Referenz.
Ich kann auch die gleiche Sache weniger verbosely schreiben:
A &&var_or_dummy = modify? std::move(my_A)
: static_cast<A&&>(A(my_A));
Jetzt ist es viel kürzer. Die erste Abkürzung ist fraglich: move
soll signalisieren, dass etwas mit dem Objekt passiert, nicht nur ein lvalue-to-xvalue-to-lvalue shuffle. Verwirrenderweise kann move
nicht nach :
verwendet werden, da der Funktionsaufruf die Bindung zwischen temporär und Referenz unterbrechen würde. Die Syntax A(my_A)
ist vielleicht klarer als die static_cast
, aber es ist technisch äquivalent zu einem C-Style-Cast.
Ich kann auch den ganzen Weg gehen und schreiben Sie es vollständig in C-Casts:
A &&var_or_dummy = modify? (A&&)(my_A) : (A&&)(A(my_A));
Nach allem, wenn dies ein Idiom sein wird, ist es zweckmäßig sein muss und static_cast
ist nicht schützt mich wirklich vor allem - die eigentliche Gefahr besteht darin, nicht direkt an my_A
im true
Fall zu binden.
Auf der anderen Seite wird dies leicht durch den Typnamen beherrscht, der dreimal wiederholt wird. Wenn A
durch eine große, hässliche Template-ID ersetzt würde, würde ich wirklich eine echte Abkürzung wollen.
(Beachten Sie, dass V
trotz erscheinen fünf Mal nur einmal ausgewertet wird :)
#define VAR_OR_DUMMY(C, V) ((C)? \
static_cast< typename std::remove_reference< decltype(V) >::type && >(V) \
: static_cast< typename std::remove_reference< decltype(V) >::type && > ( \
static_cast< typename std::remove_reference< decltype(V) >::type >(V)))
hackish als Makros sind, denke ich, dass die beste Alternative des Bündels ist. Es ist ein bisschen gefährlich, weil es einen xvalue zurückgibt, also sollte es nicht außerhalb der Referenzinitialisierung verwendet werden.
Da muss etwas sein, an das ich nicht gedacht habe ... Vorschläge?
Ohne ein Makro, ich denke, Sie können eine weitere der Erwähnungen des Typs 'A' mit Hilfe von' auto && var_or_dummy = ... 'ausschneiden. Nicht, dass das viel besser wäre ... Zu meiner Erbauung: 'VAR_OR_DUMMY' kann nicht als Funktionsvorlage implementiert werden, da das Temporäre direkt an die Rvalue-Referenz gebunden werden muss und eine Rvalue-Referenz von einer Funktion nicht richtig funktioniert ? –
@James: Kann ich 'auto' irgendwie anstelle von' remove_reference :: type' verwenden? Ja, das ist mein Denken. Ich habe versucht, dass es auch einen Lvalue-Bezug zurückgibt (siehe Edit-Verlauf), aber oh, keine Funktionen erlaubt. –
Potatoswatter
Nein, ich glaube nicht, dass "auto" anstelle der 'remove_reference :: type' verwendet werden kann (obwohl ich beim Nachschlagen festgestellt habe, dass dies gilt:' auto p = new auto (1); ' ... 'p' hat den Typ' int * '). –