funciones examples c++ lambda c++11

funciones - lambda examples c++



¿Cuál es el tiempo de vida de una expresión C++ lambda? (4)

(He leído ¿Cuál es la duración de los funtores implícitos derivados de lambda en C ++? Y no responde esta pregunta).

Entiendo que la sintaxis de C ++ lambda es simplemente un azucar para hacer una instancia de una clase anónima con un operador de llamada y un estado, y entiendo los requisitos de por vida de ese estado (decididos por si captura por valor de referencia). Pero ¿qué es? la vida útil del objeto lambda en sí? En el siguiente ejemplo, ¿la instancia std::function devuelve va a ser útil?

std::function<int(int)> meta_add(int x) { auto add = [x](int y) { return x + y; }; return add; }

Si es así, ¿cómo funciona ? Esto me parece demasiado mágico. Solo puedo imaginarlo trabajando con la std::function copiando toda mi instancia, lo que podría ser muy pesado dependiendo de lo que capture. En el pasado he usado std::function principalmente con punteros de función desnudos y copiarlos es rápido. También parece problemático a la luz del borrado de tipos de std::function .


En el código que publicaste:

std::function<int(int)> meta_add(int x) { auto add = [x](int y) { return x + y; }; return add; }

El objeto std::function<int(int)> que devuelve la función actualmente contiene una instancia movida del objeto de función lambda que se asignó a la variable local add .

Cuando define un lambda de C ++ 11 que captura el valor por valor o por referencia, el compilador de C ++ genera automáticamente un tipo funcional único, una instancia del cual se construye cuando el lambda se llama o se asigna a una variable. Para ilustrar, su compilador C ++ podría generar el siguiente tipo de clase para la lambda definida por [x](int y) { return x + y; } [x](int y) { return x + y; } :

class __lambda_373s27a { int x; public: __lambda_373s27a(int x_) : x(x_) { } int operator()(int y) const { return x + y; } };

Entonces, la función meta_add es esencialmente equivalente a:

std::function<int(int)> meta_add(int x) { __lambda_373s27a add = __lambda_373s27a(x); return add; }

EDITAR: por cierto, no estoy seguro de si usted sabe esto, pero este es un ejemplo de currying de función en C ++ 11.


Esto es:

[x](int y) { return x + y; };

Es equivalente a: (O puede considerarse también)

struct MyLambda { MyLambda(int x): x(x) {} int operator()(int y) const { return x + y; } private: int x; };

Entonces su objeto devuelve un objeto que se ve así. Que tiene un constructor de copia bien definido. Por lo tanto, parece muy razonable que se pueda copiar correctamente de una función.


La vida útil es exactamente la misma que si reemplazaras tu lambda con un functor enrollado a mano:

struct lambda { lambda(int x) : x(x) { } int operator ()(int y) { return x + y; } private: int x; }; std::function<int(int)> meta_add(int x) { lambda add(x); return add; }

El objeto será creado, local para la función meta_add , luego movido [en su entirty, incluyendo el valor de x ] en el valor de retorno, luego la instancia local saldrá del alcance y se destruirá de forma normal. Pero el objeto devuelto por la función seguirá siendo válido mientras el objeto std::function que lo contiene lo haga. Cuánto tiempo eso obviamente depende del contexto de la llamada.


Parece que estás más confundido sobre std::function que lambdas.

std::function usa una técnica llamada borrado de tipo. Aquí hay una mosca rápida.

class Base { virtual ~Base() {} virtual int call( float ) =0; }; template< typename T> class Eraser : public Base { public: Eraser( T t ) : m_t(t) { } virtual int call( float f ) override { return m_t(f); } private: T m_t; }; class Erased { public: template<typename T> Erased( T t ) : m_erased( new Eraser<T>(t) ) { } int do_call( float f ) { return m_erased->call( f ); } private: Base* m_erased; };

¿Por qué querrías borrar el tipo? ¿No es el tipo que queremos solo int (*)(float) ?

Lo que el borrado de tipo permite borrar ahora puede almacenar cualquier valor que sea invocable como int(float) .

int boring( float f); short interesting( double d ); struct Powerful { int operator() ( float ); }; Erased e_boring( &boring ); Erased e_interesting( &interesting ); Erased e_powerful( Powerful() ); Erased e_useful( []( float f ) { return 42; } );