Menu
Coddy logo textTech

Funtori ed espressioni lambda

Fa parte della sezione Programmazione orientata agli oggetti del percorso C++ di Coddy. Lezione 74 di 104.

Molti algoritmi STL accettano un oggetto chiamabile che personalizza il loro comportamento. Hai già visto le espressioni lambda usate con std::transform. Esploriamo sia i functor sia le espressioni lambda: due modi per creare oggetti chiamabili in C++.

Un funtore (oggetto funzione) è una classe che sovraccarica l'operator(), consentendo alle istanze di essere chiamate come funzioni:

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

Ogni istanza di functor può mantenere un proprio stato indipendente tramite variabili membro impostate al momento della costruzione, cosa che una normale chiamata di funzione non può fare. Tuttavia, definire una classe per operazioni semplici è prolisso. Le espressioni lambda offrono un'alternativa concisa:

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

La sintassi lambda è [capture](parameters) { body }. La clausola di cattura specifica quali variabili esterne la lambda può accedere. Usa [=] per catturare tutto per valore, [&] per catturare tutto per riferimento oppure elenca variabili specifiche come [factor] o [&factor].

Le lambda sono particolarmente utili per operazioni occasionali con algoritmi come l’ordinamento con criteri personalizzati:

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); });
// Ordina per valore assoluto: {-1, -2, 5, 8}
challenge icon

Sfida

Facile

Costruiamo un calcolatore dei prezzi che mostri sia i funtori sia le espressioni lambda per applicare diverse strategie di sconto ai prezzi dei prodotti.

Organizzerai il codice in due file:

  • Discounts.h: qui definisci i funtori per gli sconti e le funzioni di utilità.

    Crea un funtore chiamato PercentageDiscount che memorizzi una percentuale di sconto (come intero). Il suo operator() deve accettare un prezzo double e restituire il prezzo scontato. Per esempio, uno sconto del 20% su $100 deve restituire $80.

    Crea un altro funtore chiamato FixedDiscount che memorizzi un importo fisso da sottrarre (come double). Il suo operator() deve accettare un prezzo e restituire il prezzo meno l'importo fisso (senza mai scendere sotto 0).

    Crea una funzione chiamata printPrices che accetti un const std::vector<double>& e stampi tutti i prezzi separati da spazi, seguiti da una nuova riga. Formatta ogni prezzo con due cifre decimali.

  • main.cpp: leggi cinque valori (ciascuno su una riga separata):
    1. Prezzo del primo prodotto (double)
    2. Prezzo del secondo prodotto (double)
    3. Prezzo del terzo prodotto (double)
    4. Percentuale di sconto da applicare (intero, ad esempio 20 per il 20%)
    5. Importo dello sconto fisso (double)

    Crea un vettore con i tre prezzi e mostra entrambi gli approcci:

    1. Stampa Original prices: seguito dai prezzi
    2. Usa std::transform con il tuo funtore PercentageDiscount per creare un nuovo vettore di prezzi scontati. Stampa After percentage discount: seguito dai risultati
    3. Usa std::transform con il tuo funtore FixedDiscount sui prezzi originali per creare un altro vettore. Stampa After fixed discount: seguito dai risultati
    4. Usa std::transform con un'espressione lambda che raddoppi ogni prezzo originale. Stampa Premium prices (doubled): seguito dai risultati
    5. Usa std::sort con una lambda per ordinare i prezzi originali in ordine decrescente. Stampa Sorted (high to low): seguito dai prezzi ordinati

Per esempio, con gli input 100.00, 50.00, 75.00, 20 e 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 

Questa sfida ti permette di confrontare i funtori (che mantengono uno stato, come l'importo dello sconto) con le lambda (che catturano variabili per operazioni rapide e inline). Entrambi gli approcci funzionano perfettamente con algoritmi STL come std::transform e std::sort.

Provalo tu

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

int main() {
    // Leggi gli input
    double price1, price2, price3;
    int percentageDiscount;
    double fixedDiscount;
    
    std::cin >> price1;
    std::cin >> price2;
    std::cin >> price3;
    std::cin >> percentageDiscount;
    std::cin >> fixedDiscount;
    
    // Crea un vettore con i tre prezzi
    std::vector<double> prices = {price1, price2, price3};
    
    // TODO: Stampa "Original prices:" seguito dai prezzi usando printPrices
    
    // TODO: Usa std::transform con il funtore PercentageDiscount
    // Crea un nuovo vettore per i risultati
    // Stampa "After percentage discount:" seguito dai risultati
    
    // TODO: Usa std::transform con il funtore FixedDiscount sui prezzi originali
    // Crea un nuovo vettore per i risultati
    // Stampa "After fixed discount:" seguito dai risultati
    
    // TODO: Usa std::transform con una lambda che raddoppia ogni prezzo originale
    // Crea un nuovo vettore per i risultati
    // Stampa "Premium prices (doubled):" seguito dai risultati
    
    // TODO: Usa std::sort con una lambda per ordinare i prezzi originali in ordine decrescente
    // Stampa "Sorted (high to low):" seguito dai prezzi ordinati
    
    return 0;
}
quiz iconMettiti alla prova

Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.

Tutte le lezioni di Programmazione orientata agli oggetti

Esercitati da solo: Compilatore C++ online