Ejemplos de expresiones lambda

En este artículo se muestra cómo usar expresiones lambda en programas. Para ver una introducción a las expresiones lambda, consulte Expresiones lambda. Para más información sobre la estructura de una expresión lambda, consulte Sintaxis de las expresiones lambda.

Declarar expresiones lambda

Ejemplo 1

Puesto que una expresión lambda tiene tipo, puede asignarla a una variable auto o a un objeto function, como se muestra aquí:

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

El ejemplo produce la siguiente salida:

5
7

Comentarios

Para más información, consulte auto, Clase function y Llamada a función.

Aunque las expresiones lambda se suelen declarar en el cuerpo de una función, se pueden declarar en cualquier lugar donde se pueda inicializar una variable.

Ejemplo 2

El compilador de Microsoft C++ enlaza una expresión lambda a sus variables capturadas cuando se declara la expresión, no cuando se llama a la misma. En el ejemplo siguiente se muestra una expresión lambda que captura la variable local i por valor y la variable local j por referencia. Como la expresión lambda captura i por valor, la reasignación de i más adelante en el programa no afecta al resultado de la expresión. Sin embargo, puesto que la expresión lambda captura j por referencia, la reasignación de j afecta al resultado de la expresión.

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

El ejemplo produce la siguiente salida:

47

[En este artículo]

Llamar a expresiones lambda

Es posible llamar a una expresión lambda inmediatamente, como se muestra en el fragmento de código siguiente. En el segundo fragmento de código se muestra cómo pasar una expresión lambda como argumento a algoritmos de la biblioteca estándar de C++ como find_if.

Ejemplo 1

En este ejemplo se declara una expresión lambda que devuelve la suma de dos números enteros y se llama a la expresión inmediatamente con los argumentos 5 y 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;
}

El ejemplo produce la siguiente salida:

9

Ejemplo 2

En este ejemplo se pasa una expresión lambda como argumento a la función find_if. La expresión lambda devuelve true si el parámetro es un número par.

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

El ejemplo produce la siguiente salida:

The first even number in the list is 42.

Comentarios

Para más información sobre la función find_if, consulte find_if. Para más información sobre las funciones de la biblioteca estándar de C++ que realizan los algoritmos comunes, consulte <algorithm>.

[En este artículo]

Anidar expresiones lambda

Ejemplo

Se puede anidar una expresión lambda dentro de otra, como se muestra en este ejemplo. La expresión lambda interna multiplica su argumento por 2 y devuelve el resultado. La expresión lambda externa llama a la expresión lambda interna con su argumento y suma 3 al resultado.

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

El ejemplo produce la siguiente salida:

13

Comentarios

En este ejemplo, [](int y) { return y * 2; } es la expresión lambda anidada.

[En este artículo]

Funciones lambda de orden superior

Ejemplo

Muchos lenguajes de programación admiten el concepto de una función de orden superior. Una función de orden superior es una expresión lambda que toma otra expresión lambda como argumento o devuelve una expresión lambda. Se puede usar la clase function para permitir que una expresión lambda de C++ se comporte como una función de orden superior. En el ejemplo siguiente se muestra una expresión lambda que devuelve un objeto function y una expresión lambda que toma un objeto function como argumento.

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

El ejemplo produce la siguiente salida:

30

[En este artículo]

Usar una expresión lambda en una función

Ejemplo

Las expresiones lambda se pueden usar en el cuerpo de una función. La expresión lambda puede tener acceso a cualquier función o miembro de datos al que pueda tener acceso la función envolvente. Se puede capturar explícita o implícitamente el puntero this para proporcionar acceso a las funciones y miembros de datos de la clase envolvente. Visual Studio 2017 versión 15.3 y posteriores (disponible con /std:c++17 y versiones posteriores): capture this por valor ([*this]) cuando la expresión lambda se use en operaciones asincrónicas o paralelas en las que el código podría ejecutarse después de que el objeto original salga del ámbito.

Se puede usar el puntero this explícitamente en una función, como se muestra aquí:

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

También se puede capturar el puntero this de forma implícita:

void ApplyScale(const vector<int>& v) const
{
   for_each(v.begin(), v.end(),
      [=](int n) { cout << n * _scale << endl; });
}

En el ejemplo siguiente se muestra la clase Scale, que encapsula un valor de escala.

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

El ejemplo produce la siguiente salida:

3
6
9
12

Comentarios

La función ApplyScale usa una expresión lambda para imprimir el producto del valor de escala y cada elemento de un objeto vector. La expresión lambda captura implícitamente el puntero this para poder tener acceso al miembro _scale.

[En este artículo]

Usar expresiones lambda con plantillas

Ejemplo

Puesto que las expresiones lambda tienen tipo, pueden utilizarse con plantillas de C++. En el ejemplo siguiente se muestran las funciones negate_all y print_all. La función negate_all aplica el operator- unario a todos los elementos del objeto vector. La función print_all imprime en la consola todos los elementos del objeto vector.

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

El ejemplo produce la siguiente salida:

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

Comentarios

Para más información sobre las plantillas de C++, consulte Plantillas.

[En este artículo]

Controlar las excepciones

Ejemplo

El cuerpo de una expresión lambda sigue las reglas tanto del control de excepciones estructurado (SEH) como del control de excepciones de C++. Es posible controlar una excepción generada en el cuerpo de una expresión lambda o aplazar el control de excepciones al ámbito de inclusión. En el ejemplo siguiente se usa la función for_each y una expresión lambda para rellenar un objeto vector con los valores de otro. Se utiliza un bloque try/catch para controlar el acceso no válido al primer vector.

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

El ejemplo produce la siguiente salida:

Caught 'invalid vector<T> subscript'.

Comentarios

Para más información sobre el control de excepciones, consulte Control de excepciones.

[En este artículo]

Usar expresiones lambda con tipos administrados (C++/CLI)

Ejemplo

La cláusula capture de una expresión lambda no puede contener una variable que tenga un tipo administrado. Sin embargo, se puede pasar un argumento que tenga un tipo administrado a la lista de parámetros de una expresión lambda. El ejemplo siguiente contiene una expresión lambda que captura la variable local no administrada ch por valor y toma un objeto System.String como parámetro.

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

El ejemplo produce la siguiente salida:

Hello!

Comentarios

También se pueden usar expresiones lambda con la biblioteca de STL/CLR. Para más información, consulte Referencia de la biblioteca STL/CLR.

Importante

Las expresiones lambda no se admite en estas entidades administradas siguientes de Common Language Runtime (CLR): ref class, ref struct, value class y value struct.

[En este artículo]

Consulte también

Expresiones lambda
Sintaxis de la expresión lambda
auto
function (clase)
find_if
<algorithm>
Llamada a función
Templates (Plantillas [C++])
Control de excepciones
Referencia de la biblioteca STL/CLR