2011-12-12 8 views
8

Decir que tengo una especie de tipo de envoltura de una función, tal vez una función lambda:¿Qué sucede cuando se asigna un tipo que contiene un lambda?

template<typename Function> 
    struct my_struct 
{ 
    Function f; 

    my_struct(const Function &f) : f(f) {} 
}; 

¿Qué pasa cuando se asigna una instancia de este tipo? Según entiendo, las lambdas son inmutables y han eliminado operadores de asignación.

Sin embargo, cuando asigno a un objeto de este tipo en el fragmento de código siguiente, se emite ningún error:

// a structure which contains a function; 
// possibly a lambda function 
template<typename Function> 
    struct my_struct 
{ 
    Function f; 

    my_struct(const Function &f) : f(f) {} 

    // XXX adding this assignment operator causes an error 
    //my_struct &operator=(const my_struct &other) 
    //{ 
    // f = other.f; 
    // return *this; 
    //} 
}; 

template<typename Function> 
my_struct<Function> make_struct(const Function &f) 
{ 
    return my_struct<Function>(f); 
} 

int main() 
{ 
    // create some lambda 
    auto lambda = [](int x){return x;}; 

    // make a struct containing a copy of the lambda 
    auto x = make_struct(lambda); 

    // try to assign to the struct, which 
    // presumably assigns to the enclosed lambda 
    x = make_struct(lambda); 

    return 0; 
} 

Adición del operador de asignación comentado de salida produce un error, como se esperaba:

$ g++-4.6 -std=c++0x test.cpp 
test.cpp: In member function ‘my_struct<Function>& my_struct<Function>::operator=(const my_struct<Function>&) [with Function = main()::<lambda(int)>, my_struct<Function> = my_struct<main()::<lambda(int)> >]’: 
test.cpp:34:25: instantiated from here 
test.cpp:13:5: error: use of deleted function ‘main()::<lambda(int)>& main()::<lambda(int)>::operator=(const main()::<lambda(int)>&)’ 
test.cpp:27:18: error: a lambda closure type has a deleted copy assignment operator 

Entonces, ¿es posible crear tipos asignables con variables miembro lambda? Esto parece algo razonable de querer intentar. Considere combinar una lambda con boost::transform_iterator, por ejemplo.

+2

No sé mucho acerca de cómo moverme todavía, pero ¿es posible que se puedan mover pero no copiar? Puede que ya sepas la respuesta a eso, pero no conozco los factores de movimiento, así que si lo haces, por favor cuéntame. –

+0

Gracias por la idea, pero al introducir un operador de movimiento no pareció cambiar el mensaje de error. –

Respuesta

12

Estás cerca. Una lambda tiene un constructor de copia implícito y puede tener, dependiendo de los valores capturados, un constructor de movimiento implícito. Tiene un operador de copiado eliminado.

En otras palabras, puede construirlo, pero no puede asignarlo. Si está buscando un objeto de función genérico, quiere usar std::function<>. Emula funciones como valores de primera clase.


Tenga en cuenta que inmutable es diferente de asignable. Cuando un lambda se llama mutable, eso significa que su cuerpo de la función-llamada puede modificar los miembros de la lambda (es decir, la función no es const):

int i = 0; 

auto okay = [=](int x) mutable { i += x; }; 
auto error = [=](int x) { i += x; }; 

Cada uno de estos es copia-construible y no asignable.

+3

Gracias por la explicación. Es una mala tarea, se borra la asignación, parece que hace que lambda sea incompatible con '' 'boost :: transform_iterator''', al menos con su implementación actual. –

+0

Consulte [esta respuesta] (http://stackoverflow.com/a/35412456/554283) para conocer otras soluciones (utilizando std :: ref, la biblioteca propuesta de Boost Fit y la biblioteca de extensiones Boost Range propuesta). –

+0

, pero ¿cómo puede entonces std :: function hacer una copia de la lambda? –

Cuestiones relacionadas