Menu
Coddy logo textTech

Funtores y expresiones lambda

Parte de la sección Programación Orientada a Objetos del Journey de C++ de Coddy — lección 74 de 104.

Muchos algoritmos de la STL aceptan un objeto ejecutable (callable) que personaliza su comportamiento. Ya has visto lambdas utilizadas con std::transform. Exploremos tanto los functors como las expresiones lambda: dos formas de crear objetos ejecutables en C++.

Un functor (objeto de función) es una clase que sobrecarga el operator(), permitiendo que las instancias sean llamadas como funciones:

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

struct MultiplyBy {
    int factor;
    MultiplyBy(int f) : factor(f) {}
    
    int operator()(int x) const {
        return x * factor;
    }
};

int main() {
    std::vector<int> nums = {1, 2, 3, 4};
    std::vector<int> result(nums.size());
    
    std::transform(nums.begin(), nums.end(), result.begin(), MultiplyBy(3));
    // result: {3, 6, 9, 12}
}

Cada instancia de un functor puede llevar su propio estado independiente a través de variables miembro establecidas en la construcción, algo que una llamada a una función ordinaria no puede hacer. Sin embargo, definir una clase para operaciones simples resulta verboso. Las expresiones lambda proporcionan una alternativa concisa:

int factor = 3;
std::transform(nums.begin(), nums.end(), result.begin(),
               [factor](int x) { return x * factor; });

La sintaxis de lambda es [capture](parameters) { body }. La cláusula de captura especifica a qué variables externas puede acceder la lambda. Usa [=] para capturar todo por valor, [&] para capturar todo por referencia, o enumera variables específicas como [factor] o [&factor].

Las lambdas son particularmente útiles para operaciones de un solo uso con algoritmos como la ordenación con criterios personalizados:

std::vector<int> nums = {5, -2, 8, -1};
std::sort(nums.begin(), nums.end(), 
          [](int a, int b) { return std::abs(a) < std::abs(b); });
// Ordenado por valor absoluto: {-1, -2, 5, 8}
challenge icon

Desafío

Fácil

Vamos a construir una calculadora de precios que demuestre tanto los functores como las expresiones lambda para aplicar diferentes estrategias de descuento a los precios de los productos.

Organizarás tu código en dos archivos:

  • Discounts.h: Define aquí tus functores de descuento y funciones de utilidad.

    Crea un functor llamado PercentageDiscount que almacene un porcentaje de descuento (como un entero). Su operator() debe recibir un precio double y devolver el precio con el descuento aplicado. Por ejemplo, un descuento del 20% sobre $100 debería devolver $80.

    Crea otro functor llamado FixedDiscount que almacene una cantidad fija a restar (como un double). Su operator() debe recibir un precio y devolver el precio menos la cantidad fija (pero nunca por debajo de 0).

    Crea una función llamada printPrices que reciba un const std::vector<double>& e imprima todos los precios separados por espacios, seguidos de un salto de línea. Formatea cada precio con dos decimales.

  • main.cpp: Lee cinco entradas (cada una en una línea separada):
    1. Precio del primer producto (double)
    2. Precio del segundo producto (double)
    3. Precio del tercer producto (double)
    4. Porcentaje de descuento a aplicar (entero, por ejemplo, 20 para 20%)
    5. Cantidad de descuento fijo (double)

    Crea un vector con los tres precios y demuestra ambos enfoques:

    1. Imprime Original prices: seguido de los precios
    2. Usa std::transform con tu functor PercentageDiscount para crear un nuevo vector de precios con descuento. Imprime After percentage discount: seguido de los resultados
    3. Usa std::transform con tu functor FixedDiscount sobre los precios originales para crear otro vector. Imprime After fixed discount: seguido de los resultados
    4. Usa std::transform con una expresión lambda que duplique cada precio original. Imprime Premium prices (doubled): seguido de los resultados
    5. Usa std::sort con una lambda para ordenar los precios originales en orden descendente. Imprime Sorted (high to low): seguido de los precios ordenados

Por ejemplo, con las entradas 100.00, 50.00, 75.00, 20, y 15.00:

Original prices: 100.00 50.00 75.00 
After percentage discount: 80.00 40.00 60.00 
After fixed discount: 85.00 35.00 60.00 
Premium prices (doubled): 200.00 100.00 150.00 
Sorted (high to low): 100.00 75.00 50.00 

Este desafío te permite comparar functores (que mantienen un estado como la cantidad de descuento) con lambdas (que capturan variables para operaciones rápidas en línea). Ambos enfoques funcionan perfectamente con algoritmos de la STL como std::transform y std::sort.

Pruébalo tú mismo

#include <iostream>
#include <vector>
#include <algorithm>
#include "Discounts.h"

int main() {
    // Leer entradas
    double price1, price2, price3;
    int percentageDiscount;
    double fixedDiscount;
    
    std::cin >> price1;
    std::cin >> price2;
    std::cin >> price3;
    std::cin >> percentageDiscount;
    std::cin >> fixedDiscount;
    
    // Crear un vector con los tres precios
    std::vector<double> prices = {price1, price2, price3};
    
    // TODO: Imprimir "Original prices:" seguido de los precios usando printPrices
    
    // TODO: Usar std::transform con el functor PercentageDiscount
    // Crear un nuevo vector para los resultados
    // Imprimir "After percentage discount:" seguido de los resultados
    
    // TODO: Usar std::transform con el functor FixedDiscount sobre los precios originales
    // Crear un nuevo vector para los resultados
    // Imprimir "After fixed discount:" seguido de los resultados
    
    // TODO: Usar std::transform con una lambda que duplique cada precio original
    // Crear un nuevo vector para los resultados
    // Imprimir "Premium prices (doubled):" seguido de los resultados
    
    // TODO: Usar std::sort con una lambda para ordenar los precios originales de forma descendente
    // Imprimir "Sorted (high to low):" seguido de los precios ordenados
    
    return 0;
}
quiz iconPonte a prueba

Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.

Todas las lecciones de Programación Orientada a Objetos