2012-04-23 23 views
12

Estoy aprendiendo las nuevas características en C++ 11 y me encontré con este problema. Me gustaría capturar un unique_ptr moviéndolo dentro de un lambda como argumento para for_each.Cómo capturar std :: unique_ptr "por movimiento" para un lambda en std :: for_each

estableció:

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

intento 1 - no funciona porque unique_ptr no tiene un constructor de copia. C++ 0x no especifica la sintaxis paso por paso.

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

intento 2 - uso se unen para unir una copia movido de p para una función que toma int &:

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

compilador se queja de que 'result' : symbol is neither a class template nor a function template.

El objetivo principal de esta actividad es Entender cómo una variable movible puede ser capturada en un lambda que se almacena en caché para su uso posterior.

+0

Esta pregunta ya se ha formulado [aquí] (http://stackoverflow.com/q/8640393/20984). Sin embargo, no voto para cerrar porque su pregunta contiene una solución alternativa (aunque no funciona). –

+0

Ver también [aquí] (http://stackoverflow.com/q/8236521/20984). –

Respuesta

18

Actualización: puede capturar una variable móvil en una lambda desde C++ 14 en adelante.

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

No puede capturar una variable móvil en un lambda de cualquier manera sencilla en C++ 11.

Lambdas captura por copia o por referencia. Por lo tanto, para capturar una variable solo de movimiento, debe envolverla en un objeto donde copiar => mover (como std::auto_ptr). Este es un hack desagradable.

En su ejemplo, sólo puede capturar por referencia, pero si esto era sólo simplifica el código no puede hacer lo que quería con el código real:

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

Aquí está una envoltura copia-mover-solamente:

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

}; 

A continuación, puede utilizar de esta manera:

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

¿Realmente * necesita * implementar las funciones semánticas de movimiento, es decir 'move_on_copy_wrapper (move_on_copy_wrapper &&)' y 'move_on_copy_wrapper & operator = (move_on_copy_wrapper &&)'? ¿Los compilados generados no son suficientes? – Nawaz

+1

El compilador no los generará debido a la existencia del constructor de copias y el operador de asignación de copias. –

+1

"Tenga en cuenta que std :: bind también requiere que sus argumentos sean copiables". Eso no es cierto. 'std :: bind' se puede usar con tipos de solo movimiento. –

2

Su intento 2 será Almo st trabajo.

Lo que falta es que no ha dicho su llamada bind esperar un parámetro:

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

El placeholders::_1 es necesario decir el resultado de bind que debe esperar un parámetro que se le pasa por su operator().

Esta es también la sugerencia dada en la respuesta de @ marton78 here.

Cuestiones relacionadas