C ++

Expresiones lambda en C ++

Expresiones lambda en C ++

Por qué Lambda Expression?

Considere la siguiente declaración:

    int myInt = 52;

Aquí, myInt es un identificador, un lvalue. 52 es un literal, un valor. Hoy en día, es posible codificar una función especialmente y ponerla en la posición de 52. Esta función se llama expresión lambda. Considere también el siguiente programa corto:

#incluir
usando el espacio de nombres std;
int fn (int par)

int respuesta = par + 3;
devolver respuesta;

int main ()

fn (5);
return 0;

Hoy en día, es posible codificar una función especialmente y ponerla en la posición del argumento de 5, de la llamada a la función, fn (5). Esta función se llama expresión lambda. La expresión lambda (función) en esa posición es un valor pr.

Cualquier literal excepto el literal de cadena es un valor pr. La expresión lambda es un diseño de función especial que encajaría como literal en el código. Es una función anónima (sin nombre). Este artículo explica la nueva expresión primaria de C ++, denominada expresión lambda. El conocimiento básico en C ++ es un requisito para comprender este artículo.

Contenido del artículo

  • Ilustración de la expresión lambda
  • Partes de la expresión Lambda
  • Capturas
  • Esquema de función de devolución de llamada clásica con expresión Lambda
  • El tipo de retorno final
  • Cierre
  • Conclusión

Ilustración de expresión lambda

En el siguiente programa, se asigna una función, que es una expresión lambda, a una variable:

#incluir
usando el espacio de nombres std;
auto fn = [] (int param)

int respuesta = param + 3;
devolver respuesta;
;
int main ()

auto variab = fn (2);
cout << variab << '\n';
return 0;

La salida es:

    5

Fuera de la función main (), está la variable, fn. Su tipo es auto. Auto en esta situación significa que el tipo real, como int o float, está determinado por el operando derecho del operador de asignación (=). A la derecha del operador de asignación hay una expresión lambda. Una expresión lambda es una función sin el tipo de retorno anterior. Tenga en cuenta el uso y la posición de los corchetes, []. La función devuelve 5, un int, que determinará el tipo de fn.

En la función main (), está la declaración:

    auto variab = fn (2);

Esto significa que fn fuera de main () termina como el identificador de una función. Sus parámetros implícitos son los de la expresión lambda. El tipo de variab es auto.

Tenga en cuenta que la expresión lambda termina con un punto y coma, al igual que la definición de clase o estructura, termina con un punto y coma.

En el siguiente programa, una función, que es una expresión lambda que devuelve el valor 5, es un argumento para otra función:

#incluir
usando el espacio de nombres std;
void otherfn (int no1, int (* ptr) (int))

int no2 = (* ptr) (2);
cout << no1 << " << no2 << '\n';

int main ()

otherfn (4, [] (int param)

int respuesta = param + 3;
devolver respuesta;
);
return 0;

La salida es:

    4 5

Aquí hay dos funciones, la expresión lambda y la función otherfn (). La expresión lambda es el segundo argumento de otherfn (), llamado en main (). Tenga en cuenta que la función lambda (expresión) no termina con un punto y coma en esta llamada porque, aquí, es un argumento (no una función independiente).

El parámetro de la función lambda en la definición de la función otherfn () es un puntero a una función. El puntero tiene el nombre, ptr. El nombre, ptr, se usa en la definición otherfn () para llamar a la función lambda.

La declaración,

    int no2 = (* ptr) (2);

En la definición de otherfn (), llama a la función lambda con un argumento de 2. El valor de retorno de la llamada, "(* ptr) (2)" de la función lambda, se asigna a no2.

El programa anterior también muestra cómo se puede utilizar la función lambda en el esquema de función de devolución de llamada de C ++.

Partes de la expresión Lambda

Las partes de una función lambda típica son las siguientes:

    [] ()
  • [] es la cláusula de captura. Puede tener elementos.
  • () es para la lista de parámetros.
  • es para el cuerpo de la función. Si la función es independiente, debe terminar con un punto y coma.

Capturas

La definición de la función lambda puede asignarse a una variable o usarse como argumento para una llamada de función diferente. La definición de dicha llamada a función debe tener como parámetro, un puntero a una función, correspondiente a la definición de la función lambda.

La definición de la función lambda es diferente de la definición de la función normal. Puede asignarse a una variable en el ámbito global; esta función-asignada-a-variable también se puede codificar dentro de otra función. Cuando se asigna a una variable de ámbito global, su cuerpo puede ver otras variables en el ámbito global. Cuando se asigna a una variable dentro de una definición de función normal, su cuerpo puede ver otras variables en el alcance de la función solo con la ayuda de la cláusula de captura, [].

La cláusula de captura [], también conocida como el introductor lambda, permite que las variables se envíen desde el ámbito circundante (función) al cuerpo de la función de la expresión lambda. Se dice que el cuerpo de la función de la expresión lambda captura la variable cuando recibe el objeto. Sin la cláusula de captura [], no se puede enviar una variable desde el ámbito circundante al cuerpo de la función de la expresión lambda. El siguiente programa ilustra esto, con el alcance de la función main (), como el alcance circundante:

#incluir
usando el espacio de nombres std;
int main ()

int id = 5;
auto fn = [id] ()

cout << id << '\n';
;
fn ();
return 0;

La salida es 5. Sin el nombre, id, dentro de [], la expresión lambda no habría visto la variable id del alcance de la función main ().

Capturar por referencia

El ejemplo anterior de uso de la cláusula de captura es la captura por valor (consulte los detalles a continuación). Al capturar por referencia, la ubicación (almacenamiento) de la variable, e.gramo., id arriba, del alcance circundante, está disponible dentro del cuerpo de la función lambda. Entonces, cambiar el valor de la variable dentro del cuerpo de la función lambda cambiará el valor de esa misma variable en el alcance circundante. Cada variable repetida en la cláusula de captura está precedida por el ampersand (&) para lograr esto. El siguiente programa ilustra esto:

#incluir
usando el espacio de nombres std;
int main ()

int id = 5; flotar pies = 2.3; char ch = 'A';
auto fn = [& id, & ft, & ch] ()

id = 6; pies = 3.4; ch = 'B';
;
fn ();
cout << id << ", " <<  ft << ", " <<  ch << '\n';
return 0;

La salida es:

    6, 3.4, B

Confirmar que los nombres de las variables dentro del cuerpo de la función de la expresión lambda son para las mismas variables fuera de la expresión lambda.

Capturando por valor

Al capturar por valor, una copia de la ubicación de la variable, del alcance circundante, está disponible dentro del cuerpo de la función lambda. Aunque la variable dentro del cuerpo de la función lambda es una copia, su valor no se puede cambiar dentro del cuerpo a partir de ahora. Para lograr la captura por valor, cada variable repetida en la cláusula de captura no está precedida por nada. El siguiente programa ilustra esto:

#incluir
usando el espacio de nombres std;
int main ()

int id = 5; flotar pies = 2.3; char ch = 'A';
auto fn = [id, ft, ch] ()

// id = 6; pies = 3.4; ch = 'B';
cout << id << ", " <<  ft << ", " <<  ch << '\n';
;
fn ();
id = 6; pies = 3.4; ch = 'B';
cout << id << ", " <<  ft << ", " <<  ch << '\n';
return 0;

La salida es:

5, 2.3, A
6, 3.4, B

Si se quita el indicador de comentario, el programa no se compilará. El compilador emitirá un mensaje de error que indica que las variables dentro de la definición del cuerpo de la función de la expresión lambda no se pueden cambiar. Aunque las variables no se pueden cambiar dentro de la función lambda, se pueden cambiar fuera de la función lambda, como muestra la salida del programa anterior.

Capturas de mezcla

La captura por referencia y la captura por valor se pueden mezclar, como muestra el siguiente programa:

#incluir
usando el espacio de nombres std;
int main ()

int id = 5; flotar pies = 2.3; char ch = 'A'; bool bl = verdadero;
auto fn = [id, ft, & ch, & bl] ()

ch = 'B'; bl = falso;
cout << id << ", " << ft << ", " << ch << ", " << bl << '\n';
;
fn ();
return 0;

La salida es:

    5, 2.3, B, 0

Cuando todos capturados, son por referencia:

Si todas las variables que se van a capturar se capturan por referencia, entonces solo una & será suficiente en la cláusula de captura. El siguiente programa ilustra esto:

#incluir
usando el espacio de nombres std;
int main ()

int id = 5; flotar pies = 2.3; char ch = 'A'; bool bl = verdadero;
auto fn = [&] ()

id = 6; pies = 3.4; ch = 'B'; bl = falso;
;
fn ();
cout << id << ", " << ft << ", " << ch << ", " << bl << '\n';
return 0;

La salida es:

6, 3.4, B, 0

Si algunas variables deben capturarse por referencia y otras por valor, entonces una & representará todas las referencias, y el resto no irá precedido de nada, como muestra el siguiente programa:

usando el espacio de nombres std;
int main ()

int id = 5; flotar pies = 2.3; char ch = 'A'; bool bl = verdadero;
auto fn = [&, id, ft] ()

ch = 'B'; bl = falso;
cout << id << ", " << ft << ", " << ch << ", " << bl << '\n';
;
fn ();
return 0;

La salida es:

5, 2.3, B, 0

Tenga en cuenta que y solo (yo.mi., & no seguido de un identificador) tiene que ser el primer carácter en la cláusula de captura.

Cuando todos capturados, están por valor:

Si todas las variables a capturar deben ser capturadas por valor, entonces solo una = será suficiente en la cláusula de captura. El siguiente programa ilustra esto:

#incluir
usando el espacio de nombres std;
int main ()

int id = 5; flotar pies = 2.3; char ch = 'A'; bool bl = verdadero;
auto fn = [=] ()

cout << id << ", " << ft << ", " << ch << ", " << bl << '\n';
;
fn ();
return 0;

La salida es:

5, 2.3, A, 1

Nota: = es de solo lectura, a partir de ahora.

Si algunas variables deben ser capturadas por valor y otras por referencia, entonces una = representará todas las variables copiadas de solo lectura, y el resto tendrá &, como muestra el siguiente programa:

#incluir
usando el espacio de nombres std;
int main ()

int id = 5; flotar pies = 2.3; char ch = 'A'; bool bl = verdadero;
auto fn = [=, & ch, & bl] ()

ch = 'B'; bl = falso;
cout << id << ", " << ft << ", " << ch << ", " << bl << '\n';
;
fn ();
return 0;

La salida es:

5, 2.3, B, 0

Tenga en cuenta que = solo tiene que ser el primer carácter en la cláusula de captura.

Esquema de función de devolución de llamada clásica con expresión Lambda

El siguiente programa muestra cómo se puede realizar un esquema de función de devolución de llamada clásico con la expresión lambda:

#incluir
usando el espacio de nombres std;
char * salida;
auto cba = [] (char out [])

salida = fuera;
;
void principalFunc (char input [], void (* pt) (char []))

(* pt) (entrada);
cout<<"for principal function"<<'\n';

vacío fn ()

cout<<"Now"<<'\n';

int main ()

char input [] = "para función de devolución de llamada";
principalFunc (entrada, cba);
fn ();
cout<return 0;

La salida es:

para función principal
Ahora
para la función de devolución de llamada

Recuerde que cuando se asigna una definición de expresión lambda a una variable en el ámbito global, su cuerpo de función puede ver variables globales sin emplear la cláusula de captura.

El tipo de retorno final

El tipo de retorno de una expresión lambda es automático, lo que significa que el compilador determina el tipo de retorno de la expresión de retorno (si está presente). Si el programador realmente quiere indicar el tipo de retorno, lo hará como en el siguiente programa:

#incluir
usando el espacio de nombres std;
auto fn = [] (int param) -> int

int respuesta = param + 3;
devolver respuesta;
;
int main ()

auto variab = fn (2);
cout << variab << '\n';
return 0;

La salida es 5. Después de la lista de parámetros, se escribe el operador de flecha. A esto le sigue el tipo de retorno (int en este caso).

Cierre

Considere el siguiente segmento de código:

estructura Cla

int id = 5;
char ch = 'a';
obj1, obj2;

Aquí, Cla es el nombre de la clase struct.  Obj1 y obj2 son dos objetos que serán instanciados desde la clase struct. La expresión lambda es similar en implementación. La definición de la función lambda es una especie de clase. Cuando se llama (invoca) a la función lambda, se crea una instancia de un objeto a partir de su definición. Este objeto se llama cierre. Es el cierre el que hace el trabajo que se espera que haga la lambda.

Sin embargo, codificar la expresión lambda como la estructura anterior tendrá obj1 y obj2 reemplazados por los argumentos de los parámetros correspondientes. El siguiente programa ilustra esto:

#incluir
usando el espacio de nombres std;
auto fn = [] (int param1, int param2)

int respuesta = param1 + param2;
devolver respuesta;
(2, 3);
int main ()

auto var = fn;
cout << var << '\n';
return 0;

La salida es 5. Los argumentos son 2 y 3 entre paréntesis. Tenga en cuenta que la llamada a la función de expresión lambda, fn, no acepta ningún argumento, ya que los argumentos ya se han codificado al final de la definición de la función lambda.

Conclusión

La expresión lambda es una función anónima. Está en dos partes: clase y objeto. Su definición es una especie de clase. Cuando se llama a la expresión, se forma un objeto a partir de la definición. Este objeto se llama cierre. Es el cierre el que hace el trabajo que se espera que haga la lambda.

Para que la expresión lambda reciba una variable de un ámbito de función externo, necesita una cláusula de captura no vacía en su cuerpo de función.

Los mejores juegos de Oculus App Lab
Si es propietario de un visor Oculus, debe estar informado sobre la descarga lateral. Sideloading es el proceso de instalación de contenido que no es ...
Los 10 mejores juegos para jugar en Ubuntu
La plataforma Windows ha sido una de las plataformas dominantes para juegos debido al gran porcentaje de juegos que se están desarrollando hoy para ad...
5 mejores juegos de arcade para Linux
Hoy en día, las computadoras son máquinas serias que se usan para jugar. Si no puede obtener la nueva puntuación más alta, sabrá a qué me refiero. En ...