2012-04-23 15 views
12

Sto imparando le nuove funzionalità in C++ 11 e ho trovato questo problema. Mi piacerebbe catturare un unique_ptr spostandolo all'interno di una lambda come argomento per for_each.Come acquisire std :: unique_ptr "by move" per un lambda in std :: for_each

istituiti:

std::array<int,4> arr = {1,3,5,6}; 
std::unique_ptr<int> p(new int); (*p) = 3; 

tentativo 1 - non funziona perché unique_ptr non ha un costruttore di copia. C++ 0x non specifica la sintassi pass by move.

std::for_each(arr.begin(), arr.end(), [p](int& i) { i+=*p; }); 

tentativo 2 - utilizzo legano per legare una copia spostato di p ad una funzione che prende int &:

std::for_each(arr.begin(), arr.end(), 
    std::bind([](const unique_ptr<int>& p, int& i){ 
      i += (*p); 
    }, std::move(p)) 
); 

compilatore si lamenta che 'result' : symbol is neither a class template nor a function template.

Lo scopo principale dell'esercizio è quello di capire come una variabile mobile può essere catturata in un lambda che viene memorizzato nella cache per un uso successivo.

+0

Questa domanda è già stata posta [qui] (http://stackoverflow.com/q/8640393/20984). Tuttavia, non voterò per chiudere poiché la tua domanda contiene una soluzione alternativa (sebbene non funzionante). –

+0

Vedere anche [qui] (http://stackoverflow.com/q/8236521/20984). –

risposta

18

Aggiornamento: è possibile acquisire una variabile mobile in un lambda da C++ 14 in poi.

std::for_each(arr.begin(), arr.end(), [p=std::move(p)](int& i) { i+=*p; }); 

non è possibile acquisire una variabile mobile in un lambda in alcun modo diretto in C++ 11.

Lambdas cattura per copia o per riferimento. Pertanto, per acquisire una variabile di solo spostamento, è necessario avvolgerla in un oggetto in cui copiare => in movimento (ad esempio std::auto_ptr). Questo è un brutto scherzo.

Nel tuo esempio, si può semplicemente catturare per riferimento, ma se questo è stato solo semplificato il codice non può fare quello che si voleva con il codice vero e proprio:

std::for_each(arr.begin(), arr.end(), [&p](int& i) { i+=*p; }); 

Ecco un wrapper copia-move-only:

template<typename T> 
struct move_on_copy_wrapper 
{ 
    mutable T value; 

    move_on_copy_wrapper(T&& t): 
     value(std::move(t)) 
    {} 

    move_on_copy_wrapper(move_on_copy_wrapper const& other): 
     value(std::move(other.value)) 
    {} 

    move_on_copy_wrapper(move_on_copy_wrapper&& other): 
     value(std::move(other.value)) 
    {} 

    move_on_copy_wrapper& operator=(move_on_copy_wrapper const& other) 
    { 
     value=std::move(other.value); 
     return *this; 
    } 

    move_on_copy_wrapper& operator=(move_on_copy_wrapper&& other) 
    { 
     value=std::move(other.value); 
     return *this; 
    } 

}; 

è quindi possibile utilizzare in questo modo:

int main() 
{ 
    std::unique_ptr<int> p(new int(3)); 
    move_on_copy_wrapper<std::unique_ptr<int>> mp(std::move(p)); 

    [mp]() 
    { 
     std::cout<<"*mp.value="<<*mp.value<<std::endl; 
    } 
    (); 

    std::cout<<"p="<<p.get()<<", mp="<<mp.value.get()<<std::endl; 
} 
+0

Hai davvero * bisogno * di implementare le funzioni semantiche di spostamento, cioè 'move_on_copy_wrapper (move_on_copy_wrapper &&)' e 'move_on_copy_wrapper & operator = (move_on_copy_wrapper &&)'? Quelli generati dal compilatore non sono abbastanza? – Nawaz

+1

Il compilatore non li genererà a causa dell'esistenza del costruttore copia e dell'operatore di assegnazione copia. –

+1

"Nota che std: bind richiede anche che i suoi argomenti siano copiabili." Non è vero. 'std :: bind' è utilizzabile con i tipi di solo spostamento. –

2

il tentativo 2 sarà Almo lavoro.

Ciò che manca è che non hai detto a tuo bind chiamata ad aspettarsi un parametro:

std::for_each(arr.begin(), arr.end(), 
    std::bind([](const unique_ptr<int>& p, int& i){ 
     i += (*p); 
    }, std::move(p), std::placeholders::_1) 
); 

Il placeholders::_1 è necessario per raccontare il risultato di bind che dovrebbe aspettarsi un parametro passato ad esso per la sua operator().

Questo è anche il suggerimento indicato nella risposta di @ marton78 here.

Problemi correlati