2012-01-13 30 views
6

Ho tre chiamate di funzione che, a mio avviso, dovrebbero essere considerate uguali, ma chiaramente non lo sono. Sto cercando di capire perché uno dei tre non compila (g ++ -std = C++ 0x).confusione vincolo valore in C++

// Minimal example to reproduce a compile bug I want to understand. 

#include <iostream> 
#include <string> 

using namespace std; 


void bar(const string &&x) { cout << "bar: " << x << endl; } 

string returns_a_string() { return string("cow"); } 

int main(int argc, char *argv[]) 
{ 
    bar(string("horse"));  // ok 
    bar(returns_a_string()); // ok 
    string aardvark = "aardvark"; 
    bar(aardvark);   // not ok, fails to compile, error in next comment 
    /* 
     rvalue-min.cpp:29:22: error: cannot bind ‘std::string {aka std::basic_string<char>}’ lvalue to ‘const string&& {aka const std::basic_string<char>&&}’ 
     rvalue-min.cpp:10:6: error: initializing argument 1 of ‘void barR(const string&&)’ 
    */ 
} 

Questa domanda è un po 'lungo le linee di C++0x rvalue references - lvalues-rvalue binding, ma, se è risposto lì, le mie scuse, non è stato in grado di distillare fuori.

Quello che voglio è essere in grado di chiamare la mia barra delle funzioni() con qualsiasi tipo di stringa e farlo funzionare. È sufficiente definire void barR(const string &x), ma mi piacerebbe davvero capire perché.

Grazie mille per l'aiuto nel capire perché la terza chiamata è diversa.

+3

Si noti che non si può realmente fare nulla di utile con un riferimento di * costante * rvalore. In genere si vorrebbe dichiarare 'bar (std :: string &&)'. –

+0

@KerrekSB - buon punto – jma

risposta

14

Lo scopo dei parametri di riferimento del valore r è rilevare in modo specifico quando un oggetto è un valore r. Perché se un oggetto è un valore r, la funzione sa che non verrà più utilizzato, quindi può fare tutto ciò che vuole con esso. Se un valore-l potesse legarsi a un riferimento di valore r, ciò significherebbe che il rilevamento di cui stavo parlando in realtà non stava avvenendo.

Se si desidera passare un valore l a una di queste funzioni, è necessario utilizzare std::move. Passare un oggetto tramite std::move a una funzione che richiede un riferimento al valore r equivale a dire "qui, prendi questo oggetto, strappa il coraggio, non mi interessa cosa gli succede".

Per i vostri scopi, la risposta corretta è rendere il parametro const riferimento. Un valore r è perfettamente felice essendo associato a un riferimento const. Tranne che per i costruttori di mosse, non è quasi mai la cosa giusta fare i parametri di riferimento del valore r.

+0

Questa risposta non è in disaccordo con un esempio in questo articolo (Per trovare nello specifico: Ctrl + F "// Riga 31"): http://blogs.msdn.com/b/vcblog/archive/2009/02/03 /rvalue-references-c-0x-features-in-vc10-part-2.aspx –

+0

@sftrabbit: Sì, ma è d'accordo con lo standard del linguaggio (e anche con GCC, che rifiuta il codice in quell'articolo). –

+0

Grazie. Avevo notato questo errore nell'articolo precedente ma non ho mai avuto il tempo di controllarlo. –

4

È necessario utilizzare std::move. Funziona bene:

bar(std::move(aardvark)); 
+0

Abbastanza giusto, anche se impone lavoro al cliente. Buono a sapersi, però, grazie. – jma

+1

@jma: il client deve farlo perché il client sta dando il permesso esplicito per la funzione di strappare le budella dall'oggetto. (che è perché const è dispari.) Dovresti avere solo il codice (const std :: string & rhs) per prendere tutto. –