Espressioni lambda in C++
In Visual C++ un'espressione lambda (lambda) è simile a una funzione anonima che mantiene lo stato e ha accesso alle variabili disponibili nell'ambito contenitore. Questo avviene tramite la definizione di una classe e la costruzione di un oggetto di quel tipo. In questo articolo vengono definite le espressioni lambda confrontandole con altre tecniche di programmazione, vengono illustrati i vantaggi che offrono e viene fornito un esempio di base.
Informazioni sulle espressioni lambda
Molti linguaggi di programmazione supportano il concetto di funzione anonima, una funzione che dispone di un corpo, ma non di un nome. Un'espressione lambda è una tecnica di programmazione correlata alle funzioni anonime. Un'espressione lambda definisce in modo implicito una classe di oggetti funzione e costruisce un oggetto funzione di quel tipo di classe. Per altre informazioni sugli oggetti funzione, vedere Oggetti funzione.
Come esempio introduttivo di un'espressione lambda, lo standard ISO C++ ne mostra una usata nel contesto di un parametro passato alla funzione std::sort():
#include <algorithm>
#include <cmath>
void abssort(float* x, unsigned n) {
std::sort(x, x + n,
// Lambda expression begins
[](float a, float b) {
return (std::abs(a) < std::abs(b));
} // end of lambda expression
);
}
In questo articolo viene illustrato il funzionamento di questa espressione.
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.
Oggetti funzioneLambda
Quando si scrive codice, probabilmente si usano puntatori a funzione e oggetti funzione per risolvere problemi ed eseguire calcoli, in particolare quando si usano gli algoritmi STL. I puntatori a funzione e gli oggetti funzione presentano vantaggi e svantaggi: i puntatori a funzione, ad esempio, presentano un sovraccarico sintattico minimo, ma non mantengono lo stato interno a un ambito, mentre gli oggetti funzione possono mantenere lo stato, ma richiedono il sovraccarico sintattico di una definizione di classe.
Un'espressione lambda combina i vantaggi dei puntatori a funzione e degli oggetti funzione, ma non gli svantaggi. Analogamente a un oggetto funzione, un'espressione lambda è flessibile e può mantenere lo stato, ma a differenza di un oggetto funzione, la sua sintassi compressa non richiede una definizione di classe. Utilizzando le espressioni lambda, è possibile scrivere codice meno complesso e meno soggetto agli errori del codice per un oggetto funzione equivalente.
Negli esempi seguenti viene confrontato l'utilizzo di un'espressione lambda all'utilizzo di un oggetto funzione. Nel primo esempio viene usata un'espressione lambda per mostrare sulla console se ogni elemento di un oggetto vector è pari o dispari. Nel secondo esempio viene usato un oggetto funzione per eseguire la stessa attività.
Esempio 1: Utilizzo di un'espressione lambda
In questo esempio viene usata un'espressione lambda incorporata nella chiamata a funzione for_each per mostrare sulla console se ogni elemento di un oggetto vector è pari o dispari.
Codice
// even_lambda.cpp
// compile with: cl /EHsc /nologo /W4 /MTd
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
int main()
{
// Create a vector object that contains 10 elements.
vector<int> v;
for (int i = 1; i < 10; ++i) {
v.push_back(i);
}
// Count the number of even numbers in the vector by
// using the for_each function and a lambda.
int evenCount = 0;
for_each(v.begin(), v.end(), [&evenCount] (int n) {
cout << n;
if (n % 2 == 0) {
cout << " is even " << endl;
++evenCount;
} else {
cout << " is odd " << endl;
}
});
// Print the count of even numbers to the console.
cout << "There are " << evenCount
<< " even numbers in the vector." << endl;
}
Output
Commenti
Nell'esempio il terzo argomento passato alla funzione for_each è un'espressione lambda. La parte [&evenCount] specifica la clausola di acquisizione dell'espressione, (int n) specifica l'elenco di parametri, mentre la parte rimanente specifica il corpo dell'espressione.
Esempio 2: Utilizzo di un oggetto funzione
Talvolta un'espressione lambda potrebbe risultare troppo complessa da gestire per ampliare l'esempio precedente. Nell'esempio seguente viene usato un oggetto funzione, anziché un'espressione lambda, con la funzione for_each per produrre gli stessi risultati dell'Esempio 1. In entrambi gli esempi viene memorizzato il conteggio dei numeri pari in un oggetto vector. Per mantenere lo stato dell'operazione, la classe FunctorClass archivia la variabile m_evenCount per riferimento come variabile membro. Per eseguire l'operazione, FunctorClass implementa l'operatore di chiamata di funzione, operator(). Il compilatore di Visual C++ genera codice analogo per dimensioni e prestazioni al codice dell'espressione lambda dell'Esempio 1. Per un problema di base simile a quello presentato in questo articolo, la progettazione più semplice delle espressioni lambda è probabilmente preferibile alla progettazione dell'oggetto funzione. Se tuttavia si prevede che la funzionalità possa richiedere un'espansione significativa in futuro, usare la progettazione dell'oggetto funzione in modo che la manutenzione del codice risulti più facile.
Per altre informazioni su operator(), vedere Chiamata di funzione (C++). Per altre informazioni sulla funzione for_each, vedere for_each.
Codice
// even_functor.cpp
// compile with: /EHsc
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
class FunctorClass
{
public:
// The required constructor for this example.
explicit FunctorClass(int& evenCount)
: m_evenCount(evenCount) { }
// The function-call operator prints whether the number is
// even or odd. If the number is even, this method updates
// the counter.
void operator()(int n) const {
cout << n;
if (n % 2 == 0) {
cout << " is even " << endl;
++m_evenCount;
} else {
cout << " is odd " << endl;
}
}
private:
// Default assignment operator to silence warning C4512.
FunctorClass& operator=(const FunctorClass&);
int& m_evenCount; // the number of even variables in the vector.
};
int main()
{
// Create a vector object that contains 10 elements.
vector<int> v;
for (int i = 1; i < 10; ++i) {
v.push_back(i);
}
// Count the number of even numbers in the vector by
// using the for_each function and a function object.
int evenCount = 0;
for_each(v.begin(), v.end(), FunctorClass(evenCount));
// Print the count of even numbers to the console.
cout << "There are " << evenCount
<< " even numbers in the vector." << endl;
}
Output
Riepilogo
Le espressioni lambda rappresentano una tecnica di programmazione efficace ed espressiva. Per altre informazioni sulle parti e le proprietà di un'espressione lambda, vedere Sintassi delle espressioni lambda. Per informazioni sull'utilizzo delle espressioni lambda nei programmi, vedere Esempi di espressioni lambda.