Share via


Ejemplos de expresiones lambda

En este artículo se muestra cómo usar expresiones lambda en programas. Para obtener información general sobre las expresiones lambda, vea Expresiones lambda en C++. Para obtener más información sobre la estructura de una expresión lambda, vea Sintaxis de las expresiones lambda.

En este artículo

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

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í:

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

Salida

  

Comentarios

Para obtener más información, vea auto (Palabra clave) (Deducción de tipo), function (Clase) y Llamada de función (C++).

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

Ejemplo 2

El compilador de Visual 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.

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

Salida

  

[go to top]

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 de plantillas estándar (STL) 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:

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

Salida

  

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.

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

Salida

  

Comentarios

Para obtener más información sobre la función find_if, vea find_if. Para obtener más información sobre las funciones de STL que realizan algoritmos comunes, vea <algorithm>.

[go to top]

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.

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

Salida

  

Comentarios

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

[go to top]

Funciones lambda de orden superior

Ejemplo

Muchos lenguajes de programación admiten el concepto de 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 que 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.

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

Salida

  

[go to top]

Usar una expresión lambda en un método

Ejemplo

Se pueden utilizar expresiones lambda en el cuerpo de un método. La expresión lambda puede tener acceso a cualquier método o miembro de datos al que pueda tener acceso el método envolvente. Se puede capturar explícita o implícitamente el puntero this para proporcionar acceso a los métodos y miembros de datos de la clase envolvente.

Se puede usar el puntero this explícitamente en un método, como se muestra aquí:

void ApplyScale(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.

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

Salida

  

Comentarios

El método 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.

[go to top]

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.

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

Salida

  

Comentarios

Para obtener más información acerca de las plantillas de C++, vea Plantillas.

[go to top]

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.

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

Salida

  

Comentarios

Para obtener más información acerca del control de excepciones, vea Control de excepciones en Visual C++.

[go to top]

Usar expresiones lambda con tipos administrados

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

Salida

  

Comentarios

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

Importante

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

[go to top]

Vea también

Referencia

Expresiones lambda en C++

Sintaxis de las expresiones lambda

auto (Palabra clave) (Deducción de tipo)

function (Clase)

find_if

<algorithm>

Llamada de función (C++)

Control de excepciones en Visual C++

Otros recursos

Plantillas

Referencia de la biblioteca STL/CLR