Esempi di espressioni lambda
In questo articolo viene illustrato come utilizzare le espressioni lambda nei programmi. Per una panoramica delle espressioni lambda, vedere Espressioni lambda in C++. Per altre informazioni sulla struttura di un'espressione lambda, vedere Sintassi delle espressioni lambda.
Contenuto dell'articolo
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
Dichiarazioni di espressioni lambda
Esempio 1
Poiché un'espressione lambda è tipizzata, è possibile assegnarla a una variabile auto o a un oggetto funzione, come illustrato di seguito:
Codice
// 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;
}
Output
Note
Per altre informazioni, vedere Parola chiave auto (deduzione del tipo), Classe function e Chiamata di funzione (C++).
Sebbene le espressioni lambda vengano dichiarate soprattutto nel corpo di un metodo o di una funzione, è possibile dichiararle in qualsiasi posizione sia possibile inizializzare una variabile.
Esempio 2
Il compilatore Visual C++ associa un'espressione lambda alle relative variabili acquisite quando viene dichiarata un'espressione e non quando viene chiamata l'espressione. Nell'esempio seguente viene illustrata un'espressione lambda che acquisisce la variabile locale i per valore e la variabile locale j per riferimento. Poiché l'espressione lambda acquisisce i per valore, la riassegnazione successiva di i nel programma non influisce sul risultato dell'espressione. Tuttavia, poiché l'espressione lambda acquisisce j per riferimento, la riassegnazione di j influisce sul risultato dell'espressione.
Codice
// 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;
}
Output
[go to top]
Chiamata di espressioni lambda
È possibile chiamare un'espressione lambda immediatamente, come illustrato nel frammento di codice seguente. Nel secondo frammento viene illustrato come passare un'espressione lambda come argomento agli algoritmi STL (Standard Template Library) come find_if.
Esempio 1
Nell'esempio seguente viene dichiarata un'espressione lambda che restituisce la somma di due interi e chiama l'espressione immediatamente con gli argomenti 5 e 4:
Codice
// 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;
}
Output
Esempio 2
Nell'esempio seguente viene passata un'espressione lambda come argomento alla funzione find_if. L'espressione lambda restituisce true se il relativo parametro è un numero pari.
Codice
// 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;
}
}
Output
Note
Per altre informazioni sulla funzione find_if, vedere find_if. Per altre informazioni sulle funzioni STL che eseguono algoritmi comuni, vedere <algorithm>.
[go to top]
Annidamento di espressioni lambda
Esempio
È possibile annidare un'espressione lambda all'interno di un'altra, come illustrato nell'esempio. L'espressione lambda interna moltiplica il relativo argomento per 2 e restituisce il risultato. L'espressione lambda esterna chiama l'espressione lambda interna con il relativo argomento e aggiunge 3 al risultato.
Codice
// 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;
}
Output
Note
In questo esempio [](int y) { return y * 2; } è l'espressione lambda annidata.
[go to top]
Funzioni lambda di ordine superiore
Esempio
Molti linguaggi di programmazione supportano il concetto di funzione di ordine superiore. Una funzione di ordine superiore è un'espressione lambda che accetta un'altra espressione lambda come argomento o che restituisce un'espressione lambda. È possibile usare la classe function affinché un'espressione lambda C++ assuma lo stesso comportamento di una funzione di ordine superiore. Nell'esempio seguente viene illustrata un'espressione lambda che restituisce un oggetto function e un'espressione lambda che accetta un oggetto function come argomento.
Codice
// 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;
}
Output
[go to top]
Utilizzo di un'espressione lambda in un metodo
Esempio
È possibile usare le espressioni lambda nel corpo di un metodo. L'espressione lambda può accedere a qualsiasi metodo o membro dati a cui può accedere il metodo contenitore. È possibile acquisire in modo esplicito o implicito il puntatore this per fornire l'accesso ai metodi e ai membri dati della classe contenitrice.
È possibile usare il puntatore this in modo esplicito in un metodo, come illustrato di seguito:
void ApplyScale(const vector<int>& v) const
{
for_each(v.begin(), v.end(),
[this](int n) { cout << n * _scale << endl; });
}
È inoltre possibile acquisire il puntatore this in modo implicito:
void ApplyScale(const vector<int>& v) const
{
for_each(v.begin(), v.end(),
[=](int n) { cout << n * _scale << endl; });
}
Nell'esempio seguente viene illustrata la classe Scale, che incapsula un valore di scala.
// 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);
}
Output
Note
Il metodo ApplyScale utilizza un'espressione lambda per stampare il prodotto del valore di scala e ogni elemento in un oggetto vector. L'espressione lambda acquisisce in modo implicito il puntatore this in modo che possa accedere al membro _scale.
[go to top]
Utilizzo di espressioni lambda con modelli
Esempio
Poiché le espressioni lambda sono tipizzate, è possibile utilizzarle con i modelli C++. Nell'esempio seguente vengono illustrate le funzioni negate_all e print_all. La funzione negate_all applica l'operator- unario a ogni elemento dell'oggetto vector. La funzione print_all visualizza ogni elemento nell'oggetto vector nella console.
Codice
// 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);
}
Output
Note
Per altre informazioni sui modelli C++, vedere Modelli.
[go to top]
Gestione delle eccezioni
Esempio
Il corpo di un'espressione lambda segue le regole per la gestione delle eccezioni strutturate (SEH) e la gestione delle eccezioni C++. È possibile gestire un'eccezione generata nel corpo di un'espressione lambda o rinviare la gestione delle eccezioni all'ambito contenitore. Nell'esempio seguente viene utilizzata la funzione for_each e un'espressione lambda per riempire un oggetto vector con i valori di un altro oggetto. Viene utilizzato un blocco try/catch per gestire l'accesso non valido al primo vettore.
Codice
// 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;
};
}
Output
Note
Per altre informazioni sulla gestione delle eccezioni, vedere Gestione di eccezioni in Visual C++.
[go to top]
Utilizzo di espressioni lambda con tipi gestiti
Esempio
La clausola di acquisizione di un'espressione lambda non può contenere una variabile che dispone di un tipo gestito. È tuttavia possibile passare un argomento che dispone di un tipo gestito all'elenco di parametri di un'espressione lambda. L'esempio seguente contiene un'espressione lambda che acquisisce la variabile locale non gestita ch per valore e accetta un oggetto String come parametro.
Codice
// 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");
}
Output
Note
È anche possibile usare espressioni lambda con la libreria STL/CLR. Per altre informazioni, vedere Riferimenti della libreria STL/CLR.
Importante
Le espressioni lambda non sono supportate nelle entità gestite di Common Language Runtime (CLR) elencate di seguito: ref class, ref struct, value class o value struct.
[go to top]
Vedere anche
Riferimenti
Sintassi delle espressioni lambda
Parola chiave auto (deduzione del tipo)
Gestione di eccezioni in Visual C++