Explicação detalhada da expressão Lambda em C ++

Expressão lambda

Formato de expressão lambda

Expressões lambda em C ++ 11 são usadas para definir e criar objetos de função anônima para simplificar a programação.

A sintaxe do Lambda é a seguinte:

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

 

Formato do 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 você pode ver, Lambda é dividido principalmente em cinco partes: [parâmetro de objeto de função], (parâmetro de função de sobrecarga do operador), declaração mutável ou de exceção, -> tipo de valor de retorno, {corpo da função}.

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

Identifica o início de uma expressão Lambda. Esta parte deve existir e não pode ser omitida. Os parâmetros do objeto de função são passados ​​para o construtor da classe de objeto de função gerada automaticamente pelo compilador. Os parâmetros do objeto de função só podem usar as variáveis ​​locais que são visíveis no escopo do Lambda até que o Lambda seja definido (incluindo este da classe onde o Lambda está localizado). Os parâmetros do objeto de função têm os seguintes formatos:

 

① Vazio: não captura nenhum parâmetro externo, a captura é na verdade "a variável no escopo é usada diretamente no corpo da função";

② =: O corpo da função pode usar todas as variáveis ​​locais visíveis no escopo do Lambda (incluindo esta da classe onde o Lambda está localizado), e é um método de transferência de valor (equivalente ao compilador passando automaticamente todas as variáveis ​​locais por valor para nós );

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

 

 

Passe uma variável 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:

A função de Mutable é modificar o valor da variável capturada pela lista de captura dentro do corpo da função lambda, mas como eu passo os parâmetros por transferência de valor, mudar a dentro do corpo da função lambda não fará com que o a externo mude.

③ &: O corpo da função pode usar todas as variáveis ​​locais visíveis dentro do escopo do Lambda (incluindo este da classe onde Lambda está localizado), e é passado por referência (equivalente ao compilador passando automaticamente todas as variáveis ​​locais por referência para nós) ;

#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 uma única variável por referência:

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

 

 

④ isto: A variável membro na classe onde Lambda está localizado pode ser usada no corpo da função;

#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:

⑴ O protótipo da expressão lambda aqui é function <return data type (parameter data type)>, que é semelhante ao ponteiro de função na linguagem C. Na verdade, os dois são essencialmente iguais, mas a expressão lambda tem mais " captura apenas "Lista";

⑵ Lembre-se: como passamos este ponteiro, membros estáticos não podem ser chamados na classe!

O seguinte código está correto?

#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();  
}  

 

Isto está errado. Vamos explorar por que isso está errado?

O tipo de dados retornado pela expressão lambda no código acima é nulo, portanto, o resultado da expressão lambda de retorno também é nulo.

Novo uso da função 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;  
}  

 

Dê uma olhada no código acima, o código a seguir é o mais significativo:

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

 

fptr é um tipo int, por que isso?

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

 

O código equivalente é mostrado acima, de fato, o último parêntese da expressão lambda é usado para passar parâmetros.

Mas há um pré-requisito para isso. O tipo de dado retornado pela expressão lambda não pode ser nulo. Para o tipo de dado void, este formulário não está disponível, ou seja, não há variável para receber dados do tipo void.

A forma de uma expressão lambda cujo tipo de dados de valor de retorno é nulo é a seguinte:

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

 

⑤ a, & b: Passe a por valor eb por referência;

⑥ =, & a, & b. Exceto que aeb são passados ​​por referência, outros parâmetros são passados ​​por valor;

⑦ &, a, b. Exceto para a e b que são passados ​​por valor, outros parâmetros são passados ​​por referência.

Variáveis ​​que não precisam declarar tipos de dados podem ser definidas na lista de captura e usadas no corpo da função lambda:

 

Lista de parâmetros: (lista de parâmetros de função)

Identifica o parâmetro do operador sobrecarregado (). Se não houver parâmetro, esta parte pode ser omitida. Os parâmetros podem ser passados ​​por valor (como: (a, b)) e por referência (como: (& a, & b)).

declaração mutável ou exceção

Esta parte pode ser omitida. Ao passar parâmetros de objeto de função por valor, após adicionar o modificador mutável, a cópia passada pode ser modificada (observe que a cópia pode ser modificada, não o próprio valor). A declaração de exceção é usada para especificar a exceção lançada pela função, como lançar uma exceção de tipo inteiro, você pode usar throw (int).

-> Tipo de valor de retorno

Identifica o tipo do valor de retorno da função. Quando o valor de retorno é nulo ou há apenas um retorno no corpo da função (o compilador pode inferir automaticamente o tipo de valor de retorno neste momento), esta parte pode ser omitida.

{Corpo da função}

Identifica a realização da função. Esta parte não pode ser omitida, mas o corpo da função pode estar vazio.

Instancie funções anônimas

Armazene funções anônimas em variáveis, matrizes ou vetores e os transmita como parâmetros nomeados:

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

 

Função anônima lambda e conversão mútua de ponteiro de função

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

 

Observação: como as expressões lambda são mais avançadas do que os ponteiros de função, ou seja, há uma função adicional de "captura de dados externos". Portanto, quando atribuímos expressões lambda a ponteiros de função do tipo correspondente, a lista de captura [] deve ser aérea !

Acho que você gosta

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