cpp-funciones-lambda

Qué son y cómo usar las funciones lambda en C++

En C++ una función lambda es una sintaxis compacta para definir funciones anónimas, sin necesidad de declararla de forma explícita como una función tradicional.

Estas funciones son especialmente útiles para operaciones simples y rápidas. Por ejemplo, cuando se trata de operaciones en colecciones, como filtrado, mapeo o reducción.

Si quieres aprender más sobre funciones Lambda
consulta el Curso de Introducción a la Programación leer más ⯈

Sintaxis de las Funciones Lambda

La sintaxis básica de una función lambda en C++ es la siguiente:

[captura](parametros) -> tipo_retorno { cuerpo }
  • Captura: Lista de variables del entorno que la lambda puede usar.
  • Parámetros: Lista de parámetros de entrada, separados por comas si hay más de uno.
  • Tipo de Retorno: Tipo de valor que devuelve la lambda, opcional si el tipo es deducible.
  • Cuerpo: El código que se ejecuta cuando se invoca la lambda.

Ejemplo básico

Aquí tienes un ejemplo básico de una función lambda que suma dos números:

#include <iostream>

int main() {
    auto sumar = [](int x, int y) -> int {
        return x + y;
    };

    std::cout << "Suma: " << sumar(5, 3) << std::endl; // Output: 8

    return 0;
}

En este ejemplo,

  • La función lambda sumar toma dos parámetros x e y, y devuelve su suma.
  • La palabra clave auto se usa para deducir el tipo de la lambda, y -> int especifica el tipo de retorno.

Captura de variables

Las funciones lambda pueden capturar variables del contexto en el que se definen. Hay diferentes modos de captura:

  • Por valor (=): Captura una copia de las variables.
  • Por referencia (&): Captura las variables por referencia, permitiendo modificar su valor.
  • Mixta: Combinación de capturas por valor y por referencia.

Captura por valor:

#include <iostream>

int main() {
    int valor = 10;

    auto lambda = [valor]() {
        std::cout << "Valor: " << valor << std::endl;
    };

    lambda(); // Output: Valor: 10

    return 0;
}

Captura por referencia:

#include <iostream>

int main() {
    int valor = 10;

    auto lambda = [&valor]() {
        valor++;
        std::cout << "Valor: " << valor << std::endl;
    };

    lambda(); // Output: Valor: 11
    std::cout << "Valor después de la lambda: " << valor << std::endl; // Output: Valor después de la lambda: 11

    return 0;
}

Uso en funciones de orden superior

Las funciones lambda pueden ser pasadas como argumentos a otras funciones que aceptan funciones o objetos funcionales.

Ejemplo con std::function:

#include <iostream>
#include <functional>

void Ejecutar(std::function<void()> func) {
    func();
}

int main() {
    auto mensaje = []() {
        std::cout << "Hola desde una función lambda" << std::endl;
    };

    Ejecutar(mensaje);

    return 0;
}

Lambdas captura de ‘this’

Las lambdas también pueden capturar this para acceder a los miembros de la clase desde dentro de la lambda.

#include <iostream>

class MiClase {
private:
    int valor;
public:
    MiClase(int v) : valor(v) {}
    void imprimirValor() {
        auto lambda = [this]() {
            std::cout << "Valor: " << valor << std::endl;
        };
        lambda();
    }
};

int main() {
    MiClase obj(42);
    obj.imprimirValor(); // Imprime 42
    return 0;
}

En este ejemplo, la lambda captura this para acceder al miembro valor de la clase MiClase.

Lambdas Genericas

Desde C++14 las lambdas pueden ser genéricas, lo que permite trabajar con diferentes tipos de datos.

#include <iostream>

int main() {
    auto imprimir = [](auto dato) {
        std::cout << dato << std::endl;
    };
    imprimir(5);        // Imprime un entero
    imprimir(3.14);     // Imprime un flotante
    imprimir("Hola");   // Imprime una cadena de texto
    return 0;
}

En este ejemplo, la lambda imprimir es capaz de manejar diferentes tipos de datos gracias a su naturaleza genérica.

Ejemplos prácticos

Uso en algoritmos de la STL

Las funciones lambda son ampliamente utilizadas con los algoritmos de la STL, como std::sort, std::for_each, y std::find_if.

Ordenar una colección:

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> numeros = {5, 2, 9, 1, 5, 6};

    // Ordenar usando una función lambda
    std::sort(numeros.begin(), numeros.end(), [](int a, int b) {
        return a < b;
    });

    for (int num : numeros) {
        std::cout << num << " ";
    }
    std::cout << std::endl;

    return 0;
}

Filtrar una colección:

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> numeros = {1, 2, 3, 4, 5, 6};

    // Filtrar pares
    std::vector<int> pares;
    std::copy_if(numeros.begin(), numeros.end(), std::back_inserter(pares), [](int num) {
        return num % 2 == 0;
    });

    for (int num : pares) {
        std::cout << num << " ";
    }
    std::cout << std::endl;

    return 0;
}

Uso en std::for_each

La función lambda es muy útil con std::for_each para aplicar una acción a cada elemento de una colección.

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> numeros = {1, 2, 3, 4, 5};

    // Aplicar una función lambda a cada elemento
    std::for_each(numeros.begin(), numeros.end(), [](int num) {
        std::cout << num << " ";
    });
    std::cout << std::endl;

    return 0;
}