Exemplos de expressões lambda
Este artigo mostra como usar expressões lambda em seus programas. Para obter uma visão geral das expressões lambda, consulte Expressões lambda em C++. Para obter mais informações sobre a estrutura de uma expressão lambda, consulte Sintaxe da expressão lambda.
Neste artigo
Declaring Lambda Expressions
Calling Lambda Expressions
Nesting Lambda Expressions
Higher-Order Lambda Functions
Using a Lambda Expression in a Method
Using Lambda Expressions with Templates
Handling Exceptions
Using Lambda Expressions with Managed Types
Declarando expressões lambda
Exemplo 1
Como uma expressão lambda é digitada, é possível atribuí-la a uma variável auto ou a um objeto function, como mostrado aqui:
Código
// declaring_lambda_expressions1.cpp
// compile with: /EHsc /W4
#include <functional>
#include <iostream>
int main()
{
using namespace std;
// Assign the lambda expression that adds two numbers to an auto variable.
auto f1 = [](int x, int y) { return x + y; };
cout << f1(2, 3) << endl;
// Assign the same lambda expression to a function object.
function<int(int, int)> f2 = [](int x, int y) { return x + y; };
cout << f2(3, 4) << endl;
}
Saída
Comentários
Para obter mais informações, consulte Palavra-chave auto (dedução de tipo), Classe function e Chamada de função (C++).
Embora as expressões lambda sejam declaradas com mais frequência no corpo de um método ou de uma função, é possível declará-las em qualquer lugar que você possa inicializar uma variável.
Exemplo 2
O compilador do Visual C++ associa uma expressão lambda às suas variáveis capturadas quando a expressão é declarada, e não quando a expressão é chamada. O exemplo a seguir mostra uma expressão lambda que captura a variável local i por valor e a variável local j por referência. Como a expressão lambda é capturada i por valor, a reatribuição posterior de i no programa não afetará o resultado da expressão. No entanto, como a expressão lambda captura j por referência, a reatribuição de j afetará o resultado da expressão.
Código
// declaring_lambda_expressions2.cpp
// compile with: /EHsc /W4
#include <functional>
#include <iostream>
int main()
{
using namespace std;
int i = 3;
int j = 5;
// The following lambda expression captures i by value and
// j by reference.
function<int (void)> f = [i, &j] { return i + j; };
// Change the values of i and j.
i = 22;
j = 44;
// Call f and print its result.
cout << f() << endl;
}
Saída
[go to top]
Chamando expressões lambda
Você poderá chamar uma expressão lambda imediatamente, conforme mostrado no próximo trecho de código. O segundo trecho mostra como passar um lambda como argumento aos algoritmos STL, como find_if.
Exemplo 1
Este exemplo declara uma expressão lambda que retorna a soma de dois inteiros e chama a expressão imediatamente com os argumentos 5 e 4:
Código
// calling_lambda_expressions1.cpp
// compile with: /EHsc
#include <iostream>
int main()
{
using namespace std;
int n = [] (int x, int y) { return x + y; }(5, 4);
cout << n << endl;
}
Saída
Exemplo 2
Este exemplo passa uma expressão lambda como argumento para a função find_if. A expressão lambda retornará true se o parâmetro for um número par.
Código
// calling_lambda_expressions2.cpp
// compile with: /EHsc /W4
#include <list>
#include <algorithm>
#include <iostream>
int main()
{
using namespace std;
// Create a list of integers with a few initial elements.
list<int> numbers;
numbers.push_back(13);
numbers.push_back(17);
numbers.push_back(42);
numbers.push_back(46);
numbers.push_back(99);
// Use the find_if function and a lambda expression to find the
// first even number in the list.
const list<int>::const_iterator result =
find_if(numbers.begin(), numbers.end(),[](int n) { return (n % 2) == 0; });
// Print the result.
if (result != numbers.end()) {
cout << "The first even number in the list is " << *result << "." << endl;
} else {
cout << "The list contains no even numbers." << endl;
}
}
Saída
Comentários
Para obter mais informações sobre a função find_if, consulte find_if. Para obter mais informações sobre as funções STL que executam algoritmos comuns, consulte <algorithm>.
[go to top]
Aninhando expressões lambda
Exemplo
É possível aninhar uma expressão lambda dentro de outra, como mostrado neste exemplo. A expressão lambda interna multiplica seu argumento por 2 e retorna o resultado. A expressão lambda externa chama a expressão lambda interna com seu argumento e adiciona 3 ao resultado.
Código
// nesting_lambda_expressions.cpp
// compile with: /EHsc /W4
#include <iostream>
int main()
{
using namespace std;
// The following lambda expression contains a nested lambda
// expression.
int timestwoplusthree = [](int x) { return [](int y) { return y * 2; }(x) + 3; }(5);
// Print the result.
cout << timestwoplusthree << endl;
}
Saída
Comentários
Neste exemplo, [](int y) { return y * 2; } representa a expressão lambda aninhada.
[go to top]
Funções lambda de ordem superior
Exemplo
Muitas linguagens de programação oferecem suporte ao conceito de uma função de ordem superior. Uma função de ordem superior é uma expressão lambda que usa outra expressão lambda como seu argumento ou retorna uma expressão lambda. Você pode usar a classe function para permitir que uma expressão lambda C++ se comporte como uma função de ordem superior. O exemplo a seguir mostra uma expressão lambda que retorna um objeto function e uma expressão lambda que usa um objeto function como seu argumento.
Código
// higher_order_lambda_expression.cpp
// compile with: /EHsc /W4
#include <iostream>
#include <functional>
int main()
{
using namespace std;
// The following code declares a lambda expression that returns
// another lambda expression that adds two numbers.
// The returned lambda expression captures parameter x by value.
auto addtwointegers = [](int x) -> function<int(int)> {
return [=](int y) { return x + y; };
};
// The following code declares a lambda expression that takes another
// lambda expression as its argument.
// The lambda expression applies the argument z to the function f
// and multiplies by 2.
auto higherorder = [](const function<int(int)>& f, int z) {
return f(z) * 2;
};
// Call the lambda expression that is bound to higherorder.
auto answer = higherorder(addtwointegers(7), 8);
// Print the result, which is (7+8)*2.
cout << answer << endl;
}
Saída
[go to top]
Usando uma expressão lambda em um método
Exemplo
É possível usar expressões lambda no corpo de um método. A expressão lambda pode acessar qualquer método ou membro de dados que o método delimitador possa acessar. É possível capturar explicita ou implicitamente o ponteiro this para proporcionar acesso a métodos e membros de dados da classe delimitadora.
Você pode usar o ponteiro this explicitamente em um método, como mostrado aqui:
void ApplyScale(const vector<int>& v) const
{
for_each(v.begin(), v.end(),
[this](int n) { cout << n * _scale << endl; });
}
Você também pode capturar o ponteiro this implicitamente:
void ApplyScale(const vector<int>& v) const
{
for_each(v.begin(), v.end(),
[=](int n) { cout << n * _scale << endl; });
}
O exemplo a seguir mostra a classe Scale, que encapsula um valor da escala.
// method_lambda_expression.cpp
// compile with: /EHsc /W4
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
class Scale
{
public:
// The constructor.
explicit Scale(int scale) : _scale(scale) {}
// Prints the product of each element in a vector object
// and the scale value to the console.
void ApplyScale(const vector<int>& v) const
{
for_each(v.begin(), v.end(), [=](int n) { cout << n * _scale << endl; });
}
private:
int _scale;
};
int main()
{
vector<int> values;
values.push_back(1);
values.push_back(2);
values.push_back(3);
values.push_back(4);
// Create a Scale object that scales elements by 3 and apply
// it to the vector object. Does not modify the vector.
Scale s(3);
s.ApplyScale(values);
}
Saída
Comentários
O método ApplyScale usa uma expressão lambda para imprimir o produto do valor da escala e cada elemento em um objeto vector. A expressão lambda captura implicitamente this para que possa acessar o membro _scale.
[go to top]
Usando expressões lambda com modelos
Exemplo
Como as expressões lambda são digitadas, é possível usá-las com modelos C++. O exemplo a seguir mostra as funções negate_all e print_all. A função negate_all aplica o unário operator- a cada elemento no objeto vector. A função print_all imprime cada elemento no objeto vector para o console.
Código
// template_lambda_expression.cpp
// compile with: /EHsc
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
// Negates each element in the vector object. Assumes signed data type.
template <typename T>
void negate_all(vector<T>& v)
{
for_each(v.begin(), v.end(), [](T& n) { n = -n; });
}
// Prints to the console each element in the vector object.
template <typename T>
void print_all(const vector<T>& v)
{
for_each(v.begin(), v.end(), [](const T& n) { cout << n << endl; });
}
int main()
{
// Create a vector of signed integers with a few elements.
vector<int> v;
v.push_back(34);
v.push_back(-43);
v.push_back(56);
print_all(v);
negate_all(v);
cout << "After negate_all():" << endl;
print_all(v);
}
Saída
Comentários
Para obter mais informações sobre modelos C++, consulte Modelos.
[go to top]
Tratando exceções
Exemplo
O corpo de uma expressão lambda segue as regras para a manipulação de exceção estruturada (SEH) e o tratamento de exceções C++. Você pode manipular uma exceção gerada no corpo de uma expressão lambda ou adiar o tratamento de exceções para o escopo delimitador. O exemplo a seguir usa a função for_each e uma expressão lambda para preencher um objeto vector com os valores de outro. Usa um bloco try/catch para tratar o acesso inválido ao primeiro vetor.
Código
// eh_lambda_expression.cpp
// compile with: /EHsc /W4
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
// Create a vector that contains 3 elements.
vector<int> elements(3);
// Create another vector that contains index values.
vector<int> indices(3);
indices[0] = 0;
indices[1] = -1; // This is not a valid subscript. It will trigger an exception.
indices[2] = 2;
// Use the values from the vector of index values to
// fill the elements vector. This example uses a
// try/catch block to handle invalid access to the
// elements vector.
try
{
for_each(indices.begin(), indices.end(), [&](int index) {
elements.at(index) = index;
});
}
catch (const out_of_range& e)
{
cerr << "Caught '" << e.what() << "'." << endl;
};
}
Saída
Comentários
Para obter mais informações sobre o tratamento de exceções, consulte Tratamento de exceções no Visual C++.
[go to top]
Usando expressões lambda com tipos gerenciados
Exemplo
A cláusula de captura de uma expressão lambda não pode conter uma variável que tenha um tipo gerenciado. No entanto, você pode passar um argumento que tenha um tipo gerenciado para uma lista de parâmetros de uma expressão lambda. O exemplo a seguir contém uma expressão lambda que captura a variável local não gerenciada ch por valor e usa um objeto String como seu parâmetro.
Código
// managed_lambda_expression.cpp
// compile with: /clr
using namespace System;
int main()
{
char ch = '!'; // a local unmanaged variable
// The following lambda expression captures local variables
// by value and takes a managed String object as its parameter.
[=](String ^s) {
Console::WriteLine(s + Convert::ToChar(ch));
}("Hello");
}
Saída
Comentários
Você também pode usar expressões lambda com a biblioteca STL/CLR. Para obter mais informações, consulte Referência de biblioteca STL/CLR.
Importante
As lambdas não têm suporte nestas entidades gerenciadas de CLR (Common Language Runtime): ref class, ref struct, value class e value struct.
[go to top]
Consulte também
Referência
Palavra-chave auto (dedução de tipo)
Tratamento de exceções no Visual C++