Representación de acciones con funciones lambda
En C++ moderno, las expresiones lambda permiten definir funciones anónimas directamente en el punto donde se necesitan. Una lambda puede comportarse como una función normal: puede recibir argumentos, devolver valores y, además, capturar variables del entorno para formar pequeñas acciones dependientes del contexto.
Gracias a ello, las lambdas permiten representar comportamientos concretos de manera compacta, sin necesidad de definir clases o funciones adicionales. Son especialmente útiles al trabajar con los algoritmos de la biblioteca estándar (STL), ya que muchos de ellos aceptan funciones como argumentos para expresar criterios o condiciones personalizadas.
Sintaxis general de una lambda
[captura](parámetros) -> tipo_retorno {
cuerpo
};
Donde:
capturaespecifica qué variables del entorno pueden usarse dentro de la lambda. Puede hacerse por valor[=], por referencia[&]o listando variables concretas.parámetrosdefine los argumentos de la lambda (igual que en una función).tipo_retornoes opcional; suele deducirse automáticamente.cuerpocontiene el código que se ejecuta cuando se llama a la lambda.
Ejemplo 1: usar una lambda como criterio de ordenación
Una de las aplicaciones más comunes de las lambdas es definir criterios personalizados para los algoritmos de la STL, como std::sort.
#include <iostream>
#include <vector>
#include <algorithm> // std::sort
int main() {
std::vector<int> numeros = {5, 2, 8, 1, 4};
// Orden ascendente (criterio por defecto)
std::sort(numeros.begin(), numeros.end());
std::cout << "Ascendente: ";
for (int n : numeros) std::cout << n << " ";
std::cout << "\n";
// Orden descendente (criterio definido por una lambda)
std::sort(numeros.begin(), numeros.end(), [](int a, int b) {
return a > b; // Devuelve true si 'a' debe ir antes que 'b'
});
std::cout << "Descendente: ";
for (int n : numeros) std::cout << n << " ";
std::cout << "\n";
}
std::sortordena el vector usando el criterio de comparación que recibe como tercer argumento.- La lambda sustituye la necesidad de escribir una función o clase comparadora aparte.
- Cambiar el comportamiento solo requiere modificar la expresión lambda.
Ejemplo 2: lambdas que capturan variables del entorno y modifican el comportamiento
Las lambdas pueden capturar valores externos y usarlos para crear comportamientos diferentes.
En este ejemplo, definiremos dos lambdas (mayorQue y menorQue) y las usaremos con el mismo algoritmo para producir resultados distintos.
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
std::vector<int> numeros = {1, 4, 7, 2, 9, 5};
int umbral = 5;
// Lambda que determina si un número es mayor que el umbral
auto mayorQue = [umbral](int x) {
return x > umbral;
};
// Lambda que determina si un número es menor que el umbral
auto menorQue = [umbral](int x) {
return x < umbral;
};
// Buscar el primer número mayor que el umbral
auto it1 = std::find_if(numeros.begin(), numeros.end(), mayorQue);
if (it1 != numeros.end())
std::cout << "Primer número mayor que " << umbral << ": " << *it1 << "\n";
// Buscar el primer número menor que el umbral
auto it2 = std::find_if(numeros.begin(), numeros.end(), menorQue);
if (it2 != numeros.end())
std::cout << "Primer número menor que " << umbral << ": " << *it2 << "\n";
}
- Ambas lambdas capturan la variable
umbralpor valor ([umbral]), pero aplican condiciones opuestas. - El algoritmo
std::find_ifes el mismo: lo que cambia es el criterio que se le inyecta. - Así, con el mismo conjunto de datos y la misma lógica de búsqueda, obtenemos comportamientos distintos simplemente cambiando la lambda.
Hasta ahora hemos visto cómo las lambdas pueden representar acciones y personalizar algoritmos. En el siguiente apartado aprenderemos a crear funciones o métodos que acepten funciones como parámetros, lo que nos permitirá inyectar comportamientos personalizados y diseñar sistemas verdaderamente configurables y flexibles.