Lvalue-zu-rvalue-Referenzbindung

Lesezeit: 3 Minuten

Benutzer-Avatar
Kristian D’Amato

Der Compiler beschwert sich immer wieder, dass ich versuche, einen Lvalue an eine Rvalue-Referenz zu binden, aber ich kann nicht sehen, wie. Ich bin neu in C++ 11, verschiebe Semantik usw., also haben Sie bitte etwas Geduld mit mir.

Ich habe diese Funktion:

template <typename Key, typename Value, typename HashFunction, typename Equals>
Value& FastHash<Key, Value, HashFunction, Equals>::operator[](Key&& key)
{
    //  Some code here...

    Insert(key, Value()); // Compiler error here

    //   More code here.
}

die diese Methode aufruft:

template <typename Key, typename Value, typename HashFunction, typename Equals>
void FastHash<Key, Value, HashFunction, Equals>::Insert(Key&& key, Value&& value)
{
    // ...
}

Ich bekomme immer wieder Fehler wie die folgenden:

cannot convert argument 1 from 'std::string' to 'std::string &&'

beim Insert()-Aufruf. Ist nicht key als rvalue in der Operatorüberladung definiert? Warum wird es als lvalue neu interpretiert?

Insert(key, Value()); // Compiler error here

key hier ist Key&& key – das ist ein lvalue! Es hat einen Namen, und Sie können seine Adresse nehmen. Es ist nur diese Art von lvalue, die “rvalue reference to Key“.

Sie müssen einen Rvalue übergeben, und dafür müssen Sie verwenden std::move:

Insert(std::move(key), Value()); // No compiler error any more

Ich kann verstehen, warum dies kontraintuitiv ist! Aber sobald Sie zwischen einer rvalue-Referenz (die eine an einen rvalue gebundene Referenz ist) und einem tatsächlichen rvalue unterscheiden, wird es klarer.

Bearbeiten: Das eigentliche Problem hier ist die Verwendung von rvalue-Referenzen überhaupt. Es ist sinnvoll, sie in einer Funktionsvorlage zu verwenden, in der der Typ des Arguments abgeleitet wird, da dies dem Argument ermöglicht, entweder an eine lvalue-Referenz oder an eine rvalue-Referenz zu binden, aufgrund von Regeln zum Zusammenfallen von Referenzen. In diesem Artikel und Video erfahren Sie, warum: http://isocpp.org/blog/2012/11/universal-references-in-c11-scott-meyers

Allerdings wird in diesem Fall beim Aufruf der Funktion nicht auf den Typ von Key geschlossen, da dieser bereits bei der Instanziierung von der Klasse bestimmt wurde FastHash<std::string, ... >. Sie schreiben also wirklich die Verwendung von rvalue-Referenzen vor und verwenden damit std::move behebt den Code.

Ich würde Ihren Code dahingehend ändern, dass die Parameter nach Wert genommen werden:

template <typename Key, typename Value, typename HashFunction, typename Equals>
Value& FastHash<Key, Value, HashFunction, Equals>::operator[](Key key)
{
    //  Some code here...

    Insert(std::move(key), Value());

    //   More code here.
}

template <typename Key, typename Value, typename HashFunction, typename Equals>
void FastHash<Key, Value, HashFunction, Equals>::Insert(Key key, Value value)
{
    // ...
}

Machen Sie sich keine Sorgen über zusätzliche Kopien aufgrund der Verwendung von Wertargumenten – diese werden häufig vom Compiler optimiert.

  • Ist der Typ des lvalue nicht nur “Key”? Auf welche Weise bleibt die Rvalue-Referenz erhalten?

    Benutzer743382

    14. Dezember 2013 um 12:59 Uhr

  • Das funktioniert, aber ich bin mir nicht sicher, ob ich das Problem verstehe, das hvd aufgeworfen hat. Könntest du erklären?

    – Kristian D’Amato

    14. Dezember 2013 um 13:09 Uhr

  • @polkadotcadaver Ich habe meine Antwort gelöscht, weil deine einen weitaus besseren Job macht. Die Frage, die ich hatte, war eine sprachrechtliche Frage. Der Parameter key Typ hat Key&&aber es sei denn, mein Verständnis von C++ ist hier falsch, die Ausdruck key ist ein lvalue vom Typ Keykein lvalue vom Typ Key&&.

    Benutzer743382

    14. Dezember 2013 um 13:27 Uhr

  • @hvd Du hast recht; Wertigkeit ist eine Eigenschaft eines Ausdrucks, und Ausdrücke haben keinen Referenztyp, siehe [expr]/5.

    – dyp

    14. Dezember 2013 um 13:32 Uhr

  • @KristianD’Amato Ja; für C++11 verwende ich normalerweise Entwurf n3485, das kostenlos öffentlich verfügbar ist und einige Fixes für den Standard enthält (der selbst nicht kostenlos ist). Für den neuesten Entwurf, einschließlich C++1y-Features, können Sie die cplusplus-Entwurf für das Github-Repository.

    – dyp

    14. Dezember 2013 um 13:42 Uhr


1012220cookie-checkLvalue-zu-rvalue-Referenzbindung

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy