Explicación detallada de la expresión Lambda en C ++

Expresión lambda

Formato de expresión lambda

Las expresiones Lambda en C ++ 11 se utilizan para definir y crear objetos de función anónimos para simplificar la programación.

La sintaxis de Lambda es la siguiente:

[函数对象参数] (操作符重载函数参数) mutable 或 exception 声明 -> 返回值类型 {函数体}  

 

Formato de código:

#include <iostream>  
using namespace std;  
#include <algorithm>  
#include <vector>  
  
using fptr = int(*)(int& obj);  
  
int main()  
{  
    fptr fobj = [](int& obj)mutable throw(int)->int {return obj; };  
}  

 

Como puede ver, Lambda se divide principalmente en cinco partes: [parámetro de objeto de función], (parámetro de función de sobrecarga del operador), declaración mutable o de excepción, -> tipo de valor de retorno, {cuerpo de función}.

Lista de captura: [lista de parámetros de captura]

Identifica el comienzo de una expresión Lambda. Esta parte debe existir y no se puede omitir. Los parámetros del objeto de función se pasan al constructor de la clase de objeto de función generada automáticamente por el compilador. Los parámetros del objeto de función solo pueden usar aquellas variables locales que están visibles en el alcance de Lambda hasta que se define Lambda (incluida la de la clase donde se encuentra Lambda). Los parámetros del objeto de función tienen las siguientes formas:

 

① Vacío: no captura ningún parámetro externo. La captura es en realidad "la variable en el alcance se usa directamente en el cuerpo de la función";

② =: El cuerpo de la función puede usar todas las variables locales visibles en el alcance de Lambda (incluida la de la clase donde se encuentra Lambda), y es un método de transferencia de valor (equivalente a que el compilador pase automáticamente todas las variables locales por valor para nosotros );

#include <iostream>  
using namespace std;  
#include <algorithm>  
#include <vector>  
  
int main()  
{  
    int a = 10;  
    vector<int> obj{ 1,2,3,4,5 };  
    for_each(obj.begin(), obj.end(), [=](int& obj)mutable {obj += a; cout << obj << endl; });  
}  

 

 

Pasar una variable por valor:

#include <iostream>  
using namespace std;  
#include <algorithm>  
#include <vector>  
  
int main()  
{  
    int a = 10;  
    vector<int> obj{ 1,2,3,4,5 };  
    for_each(obj.begin(), obj.end(), [a](int& obj)mutable {obj += a; cout << obj << endl; });  
}  

 

 

Nota:

La función de Mutable es modificar el valor de la variable capturada por la lista de captura dentro del cuerpo de la función lambda, pero como paso los parámetros por transferencia de valor, cambiar a dentro del cuerpo de la función lambda no hará que cambie la a externa.

③ &: el cuerpo de la función puede usar todas las variables locales visibles dentro del alcance de Lambda (incluida la de la clase donde se encuentra Lambda), y se pasa por referencia (equivalente a que el compilador pase automáticamente todas las variables locales por referencia para nosotros) ;

#include <iostream>  
using namespace std;  
#include <algorithm>  
#include <vector>  
  
int main()  
{  
    int a = 10;  
    vector<int> obj{ 1,2,3,4,5 };  
    for_each(obj.begin(), obj.end(), [&](int& obj)mutable {obj += a; cout << obj << endl; });  
} 

 

 

Para capturar una sola variable por referencia:

#include <iostream>  
using namespace std;  
#include <algorithm>  
#include <vector>  
  
int main()  
{  
    int a = 10;  
    vector<int> obj{ 1,2,3,4,5 };  
    for_each(obj.begin(), obj.end(), [&a](int& obj)mutable {obj += a; cout << obj << endl; });  
} 

 

 

④ esto: la variable miembro de la clase donde se encuentra Lambda se puede utilizar en el cuerpo de la función;

#include <iostream>  
using namespace std;  
#include <algorithm>  
#include <vector>  
#include <string>  
#include <functional>  
  
class Person  
{  
public:  
    int age;  
    string name;  
public:  
    Person(int age, string name)  
    {  
        this->age = age;  
        this->name = name;  
    }  
    void ShowInf()  
    {  
        function<void()> fptr = [this]() {cout << this->name << "的年龄为" << this->age << endl; };  
        fptr(); // 调用lambda函数  
    }  
};  
  
int main()  
{  
    Person obj(12, "张三");  
    obj.ShowInf();  
} 

 

Nota:

⑴ El prototipo de la expresión lambda aquí es function <tipo de datos de retorno (tipo de datos de parámetro)>, que es similar al puntero de función en el lenguaje C. De hecho, los dos son esencialmente lo mismo, pero la expresión lambda tiene más " captura solo "Lista";

⑵ Recuerde: debido a que pasamos este puntero, los miembros estáticos no se pueden llamar en la clase.

¿Es correcto el siguiente código:

#include <iostream>  
using namespace std;  
#include <algorithm>  
#include <vector>  
#include <string>  
#include <functional>  
  
class Person  
{  
public:  
    int age;  
    string name;  
    static int mark;  
public:  
    Person(int age, string name)  
    {  
        this->age = age;  
        this->name = name;  
    }  
    function<void()> ShowInf()  
    {  
         return [this]() {cout << this->name << "的年龄为" << this->age << endl; };  // 返回lambda表达式
    }  
};  
  
int main()  
{  
    Person obj(12, "张三");  
    obj.ShowInf();  
}  

 

Esto está mal. Exploremos por qué está mal.

El tipo de datos devuelto por la expresión lambda en el código anterior es nulo, por lo que el resultado de la expresión lambda de retorno también es nulo.

Nuevo uso de la función Lambda:

#include <iostream>  
using namespace std;  
#include <algorithm>  
#include <vector>  
#include <string>  
#include <functional>  
  
class Person  
{  
public:  
    int age;  
    string name;  
    static int mark;  
public:  
    Person(int age, string name)  
    {  
        this->age = age;  
        this->name = name;  
    }  
    void ShowInf()  
    {  
        function<void()> fptr = [this]() {cout << this->name << "的年龄为" << this->age << endl; };  
        fptr(); // 调用lambda函数  
    }  
};  
  
int main()  
{  
    Person obj(12, "张三");  
    obj.ShowInf();  
    int fptr1 = [&](int obj) {cout << obj << endl; return 0; }(4); // fptr1的数据类型是int整型  
    cout << typeid(fptr1).name() << endl;  
}  

 

Eche un vistazo al código anterior, el siguiente código es el más significativo:

int fptr1 = [&](int obj) {cout << obj << endl; return 0; }(4); // fptr1的数据类型是int整型   

 

fptr es un tipo int, ¿por qué es esto?

function<int(int)> fptr1 = [&](int obj) {cout << obj << endl; return 0; };  
fptr1(4);  

 

El código equivalente se muestra arriba, de hecho, el último paréntesis de la expresión lambda se usa para pasar parámetros.

Pero hay un prerrequisito para esto. El tipo de datos devuelto por la expresión lambda no puede ser nulo. Para el tipo de datos void, este formulario no está disponible, es decir, no hay una variable para recibir datos de tipo void.

La forma de una expresión lambda cuyo tipo de datos de valor de retorno es nulo es la siguiente:

[&](int obj) {cout << obj << endl; }(9);  

 

⑤ a, & b: Pase a por valor y b por referencia;

⑥ =, & a, & b. Excepto que ayb se pasan por referencia, otros parámetros se pasan por valor;

⑦ &, a, b. A excepción de ayb que se pasan por valor, otros parámetros se pasan por referencia.

Las variables que no necesitan declarar tipos de datos pueden definirse en la lista de captura y usarse en el cuerpo de la función lambda:

 

Lista de parámetros: (lista de parámetros de función)

Identifica el parámetro del operador sobrecargado (). Si no hay parámetro, esta parte se puede omitir. Los parámetros se pueden pasar por valor (como: (a, b)) y por referencia (como: (& a, & b)).

declaración mutable o de excepción

Esta parte se puede omitir. Al pasar parámetros de objeto de función por valor, después de agregar el modificador mutable, la copia pasada se puede modificar (tenga en cuenta que la copia se puede modificar, no el valor en sí). La declaración de excepción se usa para especificar la excepción lanzada por la función, como lanzar una excepción de tipo entero, puede usar throw (int).

-> Tipo de valor devuelto

Identifica el tipo de valor de retorno de la función. Cuando el valor de retorno es nulo, o solo hay un retorno en el cuerpo de la función (el compilador puede inferir automáticamente el tipo de valor de retorno en este momento), esta parte se puede omitir.

{Cuerpo de la función}

Identifica la realización de la función, esta parte no se puede omitir, pero el cuerpo de la función puede estar vacío.

Crear instancias de funciones anónimas

Almacene funciones anónimas en variables, matrices o vectores y páselos como parámetros con nombre:

#include <iostream>  
using namespace std;  
#include <functional>  
#include <vector>  
  
int main()  
{  
    function<void(int, int)> fptr = [](int obj1, int obj2) {cout << obj1 + obj2 << endl; }; // 必须参数类型一一对应  
    fptr(1, 1);  
    vector<function<void(int, int)>> obj{ fptr };  
    obj[0](1, 2);  
    function<void(int, int)> fptr_array[1]{ fptr };  
    fptr_array[0](4, 6);  
}  

 

Función anónima lambda y conversión mutua de puntero de función

#include <iostream>  
using namespace std;  
#include <functional>  
  
using f_ptr = void(*)(int, int);  
  
int main()  
{  
    function<void(int, int)> fptr = [](int obj1, int obj2) {cout << obj1 + obj2 << endl; };  
    f_ptr fptr1 = [](int obj1, int obj2) {cout << obj1 + obj2 << endl; };  
    //f_ptr = fptr; // 不存在function<void(int,int)>对象转化至void(*)(int, int)对象  
    fptr1(1, 3);  
} 

 

Nota: Dado que las expresiones lambda son más avanzadas que los punteros de función, es decir, hay una función adicional de "captura de datos externos". Por lo tanto, cuando asignamos expresiones lambda a punteros de función del tipo correspondiente, la lista de captura [] debe ser air !

Supongo que te gusta

Origin blog.csdn.net/weixin_45590473/article/details/111396362
Recomendado
Clasificación