2013-12-14 31 views
11

Il compilatore continua a lamentarsi Sto tentando di associare un lvalue a un riferimento di rvalue, ma non riesco a vedere come. Sono nuovo di C++ 11, spostare la semantica, ecc., Quindi per favore portami con me.Lvalue to rvalue reference binding

Ho questa funzione:

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. 
} 

che chiama questo metodo:

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

continuo a ricevere errori come il seguente:

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

sulla chiamata Inserisci(). key non è definito come un valore massimo nel sovraccarico dell'operatore? Perché viene reinterpretato come un lvalue?

Grazie.

risposta

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

key qui è Key&& key - questo è un lvalue! Ha un nome e puoi prendere il suo indirizzo. È solo che quel tipo di quel valore è "rvalue reference to Key".

è necessario passare in un rvalue, e per questo è necessario utilizzare std::move:

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

Posso capire perché questo è contro-intuitivo! Ma una volta che si distingue tra e il riferimento di valore (che è un riferimento associato a un valore) e un valore effettivo, diventa più chiaro.

Modifica: il vero problema qui è usare i riferimenti di valore. Ha senso utilizzarli in un modello di funzione in cui viene dedotto il tipo di argomento, poiché ciò consente all'argomento di collegarsi a un riferimento di lvalue oa un riferimento di rvalue, a causa delle regole di compressione dei riferimenti. Vedere questo articolo e video per il motivo: http://isocpp.org/blog/2012/11/universal-references-in-c11-scott-meyers

Tuttavia, in questo caso il tipo di Chiave non viene dedotto quando viene chiamata la funzione, poiché è già stata determinata dalla classe quando è stata creata l'istanza FastHash<std::string, ... >. Quindi stai davvero prescrivendo l'uso dei riferimenti di valore, e quindi usando std::move correggi il codice.

vorrei cambiare il codice per che i parametri siano prendono per valore:

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) 
{ 
    // ... 
} 

Non preoccuparti troppo di copie extra dovuti all'uso di argomenti di valore - questi sono spesso ottimizzati dal compilatore.

+2

Non è il tipo di lvalue solo "Chiave"? In che modo il valore di riferimento-valore è ancora conservato? – hvd

+0

Funziona, ma non sono sicuro di aver capito il problema sollevato da hvd. Potresti spiegare? –

+0

@hvd Viene conservato perché non vi è alcun tipo di detrazione argomento in corso su di lei - consultare la mia modifica. – polkadotcadaver