Por que Lambda Expression?
Considere a seguinte declaração:
int myInt = 52;Aqui, myInt é um identificador, um lvalue. 52 é um literal, um prvalue. Hoje, é possível codificar uma função especialmente e colocá-la na posição de 52. Essa função é chamada de expressão lambda. Considere também o seguinte programa curto:
#incluirusando namespace std;
int fn (int par)
resposta int = par + 3;
resposta de retorno;
int main ()
fn (5);
return 0;
Hoje é possível codificar uma função especialmente e colocá-la na posição do argumento de 5, da chamada de função, fn (5). Essa função é chamada de expressão lambda. A expressão lambda (função) nessa posição é um prvalue.
Qualquer literal, exceto o literal de string, é um prvalue. A expressão lambda é um design de função especial que caberia como um literal no código. É uma função anônima (sem nome). Este artigo explica a nova expressão primária C ++, chamada de expressão lambda. Conhecimento básico em C ++ é um requisito para entender este artigo.
Conteúdo do Artigo
- Ilustração da Expressão Lambda
- Partes da Expressão Lambda
- Capturas
- Esquema de função de retorno de chamada clássico com expressão lambda
- O tipo de retorno à direita
- Fecho
- Conclusão
Ilustração da expressão lambda
No programa a seguir, uma função, que é uma expressão lambda, é atribuída a uma variável:
#incluirusando namespace std;
auto fn = [] (int param)
resposta int = param + 3;
resposta de retorno;
;
int main ()
auto variab = fn (2);
cout << variab << '\n';
return 0;
O resultado é:
5Fora da função main (), existe a variável, fn. Seu tipo é automático. Auto nesta situação significa que o tipo real, como int ou float, é determinado pelo operando certo do operador de atribuição (=). À direita do operador de atribuição está uma expressão lambda. Uma expressão lambda é uma função sem o tipo de retorno anterior. Observe o uso e a posição dos colchetes, []. A função retorna 5, um int, que determinará o tipo de fn.
Na função main (), existe a declaração:
auto variab = fn (2);Isso significa que fn fora de main () acaba sendo o identificador de uma função. Seus parâmetros implícitos são aqueles da expressão lambda. O tipo para variab é automático.
Observe que a expressão lambda termina com ponto-e-vírgula, assim como a definição de classe ou estrutura, termina com ponto-e-vírgula.
No programa a seguir, uma função, que é uma expressão lambda que retorna o valor 5, é um argumento para outra função:
#incluirusando namespace std;
void otherfn (int no1, int (* ptr) (int))
int no2 = (* ptr) (2);
cout << no1 << " << no2 << '\n';
int main ()
otherfn (4, [] (int param)
resposta int = param + 3;
resposta de retorno;
);
return 0;
O resultado é:
4 5Existem duas funções aqui, a expressão lambda e a função otherfn (). A expressão lambda é o segundo argumento do otherfn (), chamado em main (). Observe que a função lambda (expressão) não termina com um ponto e vírgula nesta chamada porque, aqui, é um argumento (não uma função autônoma).
O parâmetro da função lambda na definição da função otherfn () é um ponteiro para uma função. O ponteiro tem o nome, ptr. O nome, ptr, é usado na definição otherfn () para chamar a função lambda.
A declaração,
int no2 = (* ptr) (2);Na definição otherfn (), ele chama a função lambda com um argumento de 2. O valor de retorno da chamada, "(* ptr) (2)" da função lambda, é atribuído a no2.
O programa acima também mostra como a função lambda pode ser usada no esquema de função de retorno de chamada do C ++.
Partes da Expressão Lambda
As partes de uma função lambda típica são as seguintes:
[] ()- [] é a cláusula de captura. Pode ter itens.
- () é para a lista de parâmetros.
- é para o corpo da função. Se a função estiver isolada, ela deve terminar com um ponto e vírgula.
Capturas
A definição da função lambda pode ser atribuída a uma variável ou usada como argumento para uma chamada de função diferente. A definição para tal chamada de função deve ter como parâmetro, um ponteiro para uma função, correspondendo à definição da função lambda.
A definição da função lambda é diferente da definição da função normal. Ele pode ser atribuído a uma variável no escopo global; esta função atribuída a variável também pode ser codificada dentro de outra função. Quando atribuído a uma variável de escopo global, seu corpo pode ver outras variáveis no escopo global. Quando atribuído a uma variável dentro de uma definição de função normal, seu corpo pode ver outras variáveis no escopo da função apenas com a ajuda da cláusula de captura, [].
A cláusula de captura [], também conhecida como introdutor lambda, permite que as variáveis sejam enviadas do escopo circundante (função) para o corpo da função da expressão lambda. Diz-se que o corpo da função da expressão lambda captura a variável quando recebe o objeto. Sem a cláusula de captura [], uma variável não pode ser enviada do escopo circundante para o corpo da função da expressão lambda. O programa a seguir ilustra isso, com o escopo da função main (), como o escopo circundante:
#incluirusando namespace std;
int main ()
id int = 5;
auto fn = [id] ()
cout << id << '\n';
;
fn ();
return 0;
A saída é 5. Sem o nome, id, dentro de [], a expressão lambda não teria visto a variável id do escopo da função main ().
Capturando por Referência
O exemplo de uso da cláusula de captura acima é capturar por valor (veja os detalhes abaixo). Na captura por referência, a localização (armazenamento) da variável, e.g., id acima, do escopo circundante, é disponibilizado dentro do corpo da função lambda. Portanto, alterar o valor da variável dentro do corpo da função lambda irá alterar o valor dessa mesma variável no escopo circundante. Cada variável repetida na cláusula de captura é precedida pelo e comercial (&) para conseguir isso. O programa a seguir ilustra isso:
#incluirusando namespace std;
int main ()
id int = 5; float ft = 2.3; char ch = 'A';
auto fn = [& id, & ft, & ch] ()
id = 6; ft = 3.4; ch = 'B';
;
fn ();
cout << id << ", " << ft << ", " << ch << '\n';
return 0;
O resultado é:
6, 3.4, BConfirmando que os nomes das variáveis dentro do corpo da função da expressão lambda são para as mesmas variáveis fora da expressão lambda.
Capturando por valor
Na captura por valor, uma cópia da localização da variável, do escopo circundante, é disponibilizada dentro do corpo da função lambda. Embora a variável dentro do corpo da função lambda seja uma cópia, seu valor não pode ser alterado dentro do corpo a partir de agora. Para conseguir a captura por valor, cada variável repetida na cláusula de captura não é precedida por nada. O programa a seguir ilustra isso:
#incluirusando namespace std;
int main ()
id int = 5; float ft = 2.3; char ch = 'A';
auto fn = [id, ft, ch] ()
// id = 6; ft = 3.4; ch = 'B';
cout << id << ", " << ft << ", " << ch << '\n';
;
fn ();
id = 6; ft = 3.4; ch = 'B';
cout << id << ", " << ft << ", " << ch << '\n';
return 0;
O resultado é:
5, 2.3, A6, 3.4, B
Se o indicador de comentário for removido, o programa não irá compilar. O compilador emitirá uma mensagem de erro informando que as variáveis dentro da definição do corpo da função da expressão lambda não podem ser alteradas. Embora as variáveis não possam ser alteradas dentro da função lambda, elas podem ser alteradas fora da função lambda, como mostra a saída do programa acima.
Mistura de capturas
A captura por referência e a captura por valor podem ser misturadas, como mostra o programa a seguir:
#incluirusando namespace std;
int main ()
id int = 5; float ft = 2.3; char ch = 'A'; bool bl = verdadeiro;
auto fn = [id, ft, & ch, & bl] ()
ch = 'B'; bl = falso;
cout << id << ", " << ft << ", " << ch << ", " << bl << '\n';
;
fn ();
return 0;
O resultado é:
5, 2.3, B, 0Quando todos são capturados, são por referência:
Se todas as variáveis a serem capturadas são capturadas por referência, então apenas uma & será suficiente na cláusula de captura. O programa a seguir ilustra isso:
#incluirusando namespace std;
int main ()
id int = 5; float ft = 2.3; char ch = 'A'; bool bl = verdadeiro;
auto fn = [&] ()
id = 6; ft = 3.4; ch = 'B'; bl = falso;
;
fn ();
cout << id << ", " << ft << ", " << ch << ", " << bl << '\n';
return 0;
O resultado é:
6, 3.4, B, 0Se algumas variáveis devem ser capturadas por referência e outras por valor, então um & representará todas as referências, e o resto não será precedido por nada, como mostra o programa a seguir:
usando namespace std;int main ()
id int = 5; float ft = 2.3; char ch = 'A'; bool bl = verdadeiro;
auto fn = [&, id, ft] ()
ch = 'B'; bl = falso;
cout << id << ", " << ft << ", " << ch << ", " << bl << '\n';
;
fn ();
return 0;
O resultado é:
5, 2.3, B, 0Observe que & sozinho (i.e., & não seguido por um identificador) deve ser o primeiro caractere na cláusula de captura.
Quando todos capturados, são por valor:
Se todas as variáveis a serem capturadas devem ser capturadas por valor, então apenas um = será suficiente na cláusula de captura. O programa a seguir ilustra isso:
#incluirusando namespace std;
int main ()
id int = 5; float ft = 2.3; char ch = 'A'; bool bl = verdadeiro;
auto fn = [=] ()
cout << id << ", " << ft << ", " << ch << ", " << bl << '\n';
;
fn ();
return 0;
O resultado é:
5, 2.3, A, 1Observação: = é somente leitura, a partir de agora.
Se algumas variáveis devem ser capturadas por valor e outras por referência, então um = representará todas as variáveis copiadas somente leitura, e o resto terá cada um &, como mostra o programa a seguir:
#incluirusando namespace std;
int main ()
id int = 5; float ft = 2.3; char ch = 'A'; bool bl = verdadeiro;
auto fn = [=, & ch, & bl] ()
ch = 'B'; bl = falso;
cout << id << ", " << ft << ", " << ch << ", " << bl << '\n';
;
fn ();
return 0;
O resultado é:
5, 2.3, B, 0Observe que = sozinho deve ser o primeiro caractere na cláusula de captura.
Esquema de função de retorno de chamada clássico com expressão lambda
O programa a seguir mostra como um esquema de função de retorno de chamada clássico pode ser feito com a expressão lambda:
#incluirusando namespace std;
saída char *;
cba automático = [] (caractere fora [])
output = out;
;
void principalFunc (char input [], void (* pt) (char []))
(* pt) (entrada);
cout<<"for principal function"<<'\n';
void fn ()
cout<<"Now"<<'\n';
int main ()
entrada char [] = "para função de retorno de chamada";
principalFunc (entrada, cba);
fn ();
cout<