Condividi tramite


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. Per altre informazioni sulla struttura di un'espressione lambda, vedere Lambda Expression Syntax.For more information about the structure of a lambda expression expression, see Lambda Expression Syntax.

Dichiarazione di espressioni lambda

Esempio 1

Poiché un'espressione lambda è tipizzata, è possibile assegnarla a una auto variabile o a un function oggetto, come illustrato di seguito:

// 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;
}

L'esempio produce il seguente output:

5
7

Osservazioni:

Per altre informazioni, vedere auto, function Classe e Chiamata di funzione.

Sebbene le espressioni lambda vengano dichiarate soprattutto nel corpo di una funzione, è possibile dichiararle in qualsiasi posizione sia possibile inizializzare una variabile.

Esempio 2

Il compilatore Microsoft C++ associa un'espressione lambda alle variabili acquisite quando l'espressione viene dichiarata anziché 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 per i valore, la riassegnazione di i più avanti 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.

// 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;
}

L'esempio produce il seguente output:

47

[Contenuto dell'articolo]

Chiamata di espressioni lambda

È possibile chiamare un'espressione lambda immediatamente, come illustrato nel frammento di codice seguente. Il secondo frammento di codice mostra come passare un'espressione lambda come argomento agli algoritmi della libreria standard C++, ad find_ifesempio .

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:

// 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;
}

L'esempio produce il seguente output:

9

Esempio 2

Nell'esempio seguente viene passata un'espressione lambda come argomento alla funzione find_if. L'espressione lambda restituisce true se il parametro è un numero pari.

// 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;
    }
}

L'esempio produce il seguente output:

The first even number in the list is 42.

Osservazioni:

Per altre informazioni sulla find_if funzione, vedere find_if. Per altre informazioni sulle funzioni della libreria standard C++ che eseguono algoritmi comuni, vedere <algorithm>.

[Contenuto dell'articolo]

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.

// 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;
}

L'esempio produce il seguente output:

13

Osservazioni:

In questo esempio [](int y) { return y * 2; } è l'espressione lambda annidata.

[Contenuto dell'articolo]

Funzioni lambda di ordine superiore

Esempio

Molti linguaggi di programmazione supportano il concetto di una funzione di ordine superiore. Una funzione di ordine superiore è un'espressione lambda che accetta un'altra espressione lambda come argomento o restituisce un'espressione lambda. È possibile usare la function classe per abilitare un'espressione lambda C++ per comportarsi come 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.

// 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;
}

L'esempio produce il seguente output:

30

[Contenuto dell'articolo]

Uso di un'espressione lambda in una funzione

Esempio

È possibile usare le espressioni lambda nel corpo di una funzione. L'espressione lambda può accedere a qualsiasi funzione o membro dati a cui può accedere la funzione contenitrice. È possibile acquisire in modo esplicito o implicito il this puntatore per fornire l'accesso alle funzioni e ai membri dati della classe contenitore. Visual Studio 2017 versione 15.3 e successive (Disponibile con /std:c++17 e versioni successive): Acquisisci this per valore ([*this]) quando l'espressione lambda verrà usata in operazioni asincrone o parallele in cui il codice potrebbe essere eseguito dopo che l'oggetto originale esce dall'ambito.

È possibile usare il this puntatore in modo esplicito in una funzione, come illustrato di seguito:

// capture "this" by reference
void ApplyScale(const vector<int>& v) const
{
   for_each(v.begin(), v.end(),
      [this](int n) { cout << n * _scale << endl; });
}

// capture "this" by value (Visual Studio 2017 version 15.3 and later)
void ApplyScale2(const vector<int>& v) const
{
   for_each(v.begin(), v.end(),
      [*this](int n) { cout << n * _scale << endl; });
}

È anche possibile acquisire il this puntatore 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.

// function_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. doesn't modify the vector.
    Scale s(3);
    s.ApplyScale(values);
}

L'esempio produce il seguente output:

3
6
9
12

Osservazioni:

La funzione ApplyScale usa un'espressione lambda per stampare il prodotto del valore di scala e ogni elemento in un oggetto vector. L'espressione lambda acquisisce this in modo implicito in modo che possa accedere al _scale membro.

[Contenuto dell'articolo]

Uso 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 negate_all funzione applica la unaria operator- a ogni elemento dell'oggetto vector . La funzione print_all visualizza ogni elemento nell'oggetto vector nella console.

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

L'esempio produce il seguente output:

34
-43
56
After negate_all():
-34
43
-56

Osservazioni:

Per altre informazioni sui modelli C++, vedere Modelli.

[Contenuto dell'articolo]

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 usata la for_each funzione e un'espressione lambda per riempire un vector oggetto con i valori di un altro oggetto. Usa un try/catch blocco per gestire l'accesso non valido al primo vettore.

// 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;
    };
}

L'esempio produce il seguente output:

Caught 'invalid vector<T> subscript'.

Osservazioni:

Per altre informazioni sulla gestione delle eccezioni, vedere Gestione delle eccezioni.

[Contenuto dell'articolo]

Uso di espressioni lambda con tipi gestiti (C++/CLI)

Esempio

La clausola capture di un'espressione lambda non può contenere una variabile con 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 System.String come parametro.

// 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");
}

L'esempio produce il seguente output:

Hello!

Osservazioni:

È anche possibile usare espressioni lambda con la libreria STL/CLR. Per altre informazioni, vedere Informazioni di riferimento sulla libreria STL/CLR.

Importante

Le espressioni lambda non sono supportate in queste entità ref classgestite CLR (Common Language Runtime): , ref structvalue class, e value struct.

[Contenuto dell'articolo]

Vedi anche

Espressioni lambda
Sintassi delle espressioni lambda
auto
function Classe
find_if
<algorithm>
Chiamata di funzione
Modelli
Gestione delle eccezioni
Riferimenti alla libreria STL/CLR