2012-04-14 15 views
8

Un tipo di ritorno come questo rappresenta qualcosa di significativo in C++ 11?semantica del tipo di ritorno di riferimento valore-r?

template <typename R> 
R&& grabStuff(); 

T instance = grabStuff<T>(); 

Spero che grabStuff dovrebbe gettare un errore di compilazione se R non hai un costruttore mossa, dal momento che questo sembrerebbe non consentire il tipo di ritorno di utilizzare un costruttore di copia

risposta

5

Come sempre, quando si restituiscono riferimenti è necessario restituire un riferimento a qualcosa che è ancora vivo dopo che la funzione è tornata. Come lo fai, dipende da te. Esempio:

T global_thing; 

T && get() { return std::move(global_thing); } 

struct Foo { Foo(T &&); /* ... */ }; 

int main() 
{ 
    global_thing.reset(); 
    Foo a(get()); 
    global_thing.reset(); 
    Foo b(get()); 
} 

L'esempio più tipico per la restituzione di un riferimento rvalue è std::move per sé, però, che restituisce un riferimento alla cosa che si passa in esso (e quindi è responsabilità del chiamante di fornire un input valido) .

+0

L'oggetto non deve essere un oggetto globale. Un oggetto locale che gestisce le risorse è anche un esempio (voglio dire, forse: D). – Nawaz

+0

@Kerrek, quindi quello che stai dicendo è che questa funzione dovrebbe essere chiamata solo nei provvisori? il risultato di 'get()' nel tuo esempio non può essere assegnato ad un riferimento normale di 'Foo &'? – lurscher

+0

@Nawaz: Sì sì, come ho detto, dipende da te ... Volevo solo dare un esempio che * non * 'std :: move' stesso. –

1

Può essere significativo a seconda di cosa vuoi fare con esso e di come hai implementato la funzione.

Infatti, std::move tipo di ritorno è T&& (riferimento rvalue), che è significativo, poiché definisce lo scopo dell'esistenza di std::move nella libreria C++ 11:

+0

'std :: move' è l'istanza ** solo ** significativa di un tipo di ritorno di riferimento rvalore. Non sarebbe mai significativo nel codice utente. – ildjarn

+0

@ildjarn: non posso affermare che * "Sarebbe ** ** mai ** significativo nel codice utente" *. Sto solo affermando che il riferimento al valore di ritorno come tipo di ritorno, può essere significativo. – Nawaz

+0

Lo sto affermando. ; -] In _user code_ (a meno che quel codice utente non stia duplicando 'std :: move' per qualche strana ragione), un tipo di ritorno di riferimento rvalore non può fare nulla di semanticamente significativo. – ildjarn

1

Se il tipo di ritorno di una funzione è un riferimento di rvalue, il risultato della chiamata di funzione è un valore x; se il tipo di ritorno è non di riferimento, il risultato della chiamata di funzione è un valore di prvalore.

Sia xvalue sia il valore di prvalore sono rvalori, ci sono alcune differenze minori tra di loro, più simili alle differenze tra riferimento e non riferimento. Ad esempio, un xvalue può avere un tipo incompleto, mentre un valore prenuativo deve di solito avere un tipo completo o il tipo void. Quando typeid viene applicato a un valore x il cui tipo è un tipo di classe polimorfico, il risultato si riferisce al tipo dinamico; e per il valore nominale, il risultato si riferisce al tipo statico.

Per la dichiarazione dichiarazione T instance = grabStuff<T>();, se T è un tipo di classe, penso che non vi sia alcuna differenza tra xvalue e prvalue in questo contesto.

L'inizializzatore è un valore rvalore, quindi il compilatore preferisce un costruttore di movimento. Ma se non viene dichiarato alcun costruttore di movimento, e viene dichiarato un costruttore di copie con parametro const riferimento, verrà scelto questo costruttore di copia e non ci sono errori. Non so perché vuoi che questo sia un errore. Se questo è un errore, qualsiasi vecchio codice sarà errato durante la copia-inizializzazione di alcuni oggetti da un valore rvalue.

Problemi correlati