C++ Academy · Lezione

Scegliere i callable

Lambda, bind o puntatori

Lezione 4 di 413 passaggi

Scegliere i callable è una lezione C++ Academy gratuita su CoddyKit. Questa è la lezione 4 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento C++ Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso C++ Academy include 4 lezioni in totale.

La cassetta degli attrezzi dei callable

Il C++ offre diversi modi per passare i comportamenti: puntatori a funzione, lambda, functor, std::bind e std::function. Ognuno è adatto a esigenze diverse.

  • Il compromesso abituale è tra velocità e flessibilità.
  • Anche la leggibilità è importante.
#include <iostream>

int twice(int x) { return x * 2; }

int main() {
    int (*fp)(int) = twice;
    auto lam = [](int x) { return x * 2; };
    std::cout << fp(5) << ' ' << lam(5) << '\n';
    return 0;
}

Quando usare un puntatore a funzione

Scelga un puntatore a funzione quando ha bisogno di una piccola callback senza stato e desidera la compatibilità con il C o un overhead nullo.

#include <iostream>

void logMsg(const char* m) { std::cout << "LOG: " << m << '\n'; }

int main() {
    void (*handler)(const char*) = logMsg;
    handler("started");
    return 0;
}

Quando usare una lambda

Una lambda è la scelta predefinita nel C++ moderno: è concisa, può catturare lo stato e il compilatore la integra bene nei template e negli algoritmi.

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

int main() {
    std::vector<int> v = {3, 1, 4, 1, 5};
    std::sort(v.begin(), v.end(), [](int a, int b) { return a > b; });
    for (int x : v) std::cout << x << ' ';
    std::cout << '\n';
    return 0;
}

Catturare lo stato in una lambda

Le lambda catturano le variabili circostanti, cosa che i puntatori a funzione non possono fare, e sono quindi ideali per callback sensibili al contesto.

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

int main() {
    int threshold = 3;
    std::vector<int> v = {1, 2, 3, 4, 5};
    int c = std::count_if(v.begin(), v.end(), [threshold](int x) { return x > threshold; });
    std::cout << c << '\n';
    return 0;
}

Quando usare un functor

Un functor (una struct con operator()) è adatto a un'operazione riutilizzabile e denominata, che può contenere una configurazione ed essere usata in più punti.

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

struct AboveThreshold {
    int limit;
    bool operator()(int x) const { return x > limit; }
};

int main() {
    std::vector<int> v = {1, 5, 2, 8};
    std::cout << std::count_if(v.begin(), v.end(), AboveThreshold{4}) << '\n';
    return 0;
}

Lambda o bind

Entrambi consentono di preimpostare gli argomenti. La versione con lambda è generalmente più chiara e più facile da ottimizzare per il compilatore, quindi la preferisca a std::bind.

#include <iostream>

int power(int base, int exp) {
    int r = 1;
    for (int i = 0; i < exp; ++i) r *= base;
    return r;
}

int main() {
    auto square = [](int x) { return power(x, 2); };
    std::cout << square(6) << '\n';
    return 0;
}

Quando usare std::function

Usi std::function quando deve memorizzare un oggetto chiamabile di tipo concreto sconosciuto, ad esempio in un membro di classe o in un contenitore.

#include <iostream>
#include <functional>
#include <vector>

int main() {
    std::vector<std::function<int(int)>> pipeline;
    pipeline.push_back([](int x) { return x + 1; });
    pipeline.push_back([](int x) { return x * 3; });
    int v = 2;
    for (auto& f : pipeline) v = f(v);
    std::cout << v << '\n';
    return 0;
}

I template evitano l'overhead

Se una funzione deve solo ricevere un oggetto chiamabile, senza memorizzarlo, un parametro template mantiene le massime prestazioni evitando il type erasure.

#include <iostream>

template <typename F>
int applyTwice(int x, F f) { return f(f(x)); }

int main() {
    std::cout << applyTwice(3, [](int n) { return n + 10; }) << '\n';
    return 0;
}

Classifica delle prestazioni

In linea di massima: un oggetto chiamabile basato su template o una lambda senza catture sono le soluzioni più veloci, un puntatore a funzione è quasi altrettanto veloce e std::function è il più lento a causa dell'indirezione e della possibile allocazione.

#include <iostream>
#include <functional>

int main() {
    auto fast = [](int x) { return x + 1; };
    std::function<int(int)> flexible = fast;
    std::cout << fast(1) << ' ' << flexible(1) << '\n';
    return 0;
}

Una guida alla scelta

Guida rapida:

  • Deve memorizzare un oggetto chiamabile qualsiasi? std::function.
  • Deve solo riceverne uno in una funzione generica? Un parametro template.
  • Comportamento inline con stato? Lambda.
  • API C o comportamento senza stato? Puntatore a funzione.
#include <iostream>
#include <functional>

void runStored(const std::function<void()>& cb) { cb(); }

template <typename F>
void runGeneric(F f) { f(); }

int main() {
    runStored([] { std::cout << "stored\n"; });
    runGeneric([] { std::cout << "generic\n"; });
    return 0;
}

Mettere insieme tutti gli elementi

Un piccolo sistema di eventi potrebbe ricevere i gestori in modo generico, ma memorizzarli in std::function per poterli invocare in seguito.

#include <iostream>
#include <functional>
#include <vector>

struct Dispatcher {
    std::vector<std::function<void(int)>> handlers;
    template <typename F> void on(F f) { handlers.emplace_back(f); }
    void fire(int e) { for (auto& h : handlers) h(e); }
};

int main() {
    Dispatcher d;
    d.on([](int e) { std::cout << "got " << e << '\n'; });
    d.fire(7);
    return 0;
}

Verifica rapida

Verifichi la Sua comprensione della scelta degli oggetti chiamabili.

Riepilogo

Ha imparato a scegliere un oggetto chiamabile:

  • puntatore a funzione per callback senza stato e compatibili con il C
  • lambda come scelta predefinita per comportamenti inline con stato
  • functor per operazioni denominate e riutilizzabili
  • parametro template quando deve solo ricevere un oggetto chiamabile, con le massime prestazioni
  • std::function quando deve memorizzare un oggetto di tipo sconosciuto

Ha completato il corso sugli oggetti funzione e std::bind.

Gratis per iniziare

Impara C++ con un tutor IA — gratis

Scrivi ed esegui vero codice nel tuo browser, ricevi aiuto istantaneo da un tutor IA disponibile 24/7, e riprendi da dove hai lasciato sul web o nell'app.

Corsi
51
Lezioni
203

Domande Frequenti

La lezione «Scegliere i callable» è gratuita?

Sì — il testo completo di «Scegliere i callable» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso C++ Academy, passa a CoddyKit PRO. Il corso C++ Academy include 4 lezioni in totale.

Cosa imparerò in «Scegliere i callable»?

Lambda, bind o puntatori Eserciti C++ Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.

Ho bisogno di esperienza per iniziare C++ Academy?

Non è richiesta alcuna esperienza precedente. C++ Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 4 di 4.

Quanto tempo richiede la lezione «Scegliere i callable»?

La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.

Posso scrivere ed eseguire codice in questa lezione C++ Academy?

Sì. Ogni lezione C++ Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.

Tutte le lezioni di questo corso

  1. Puntatori a funzione
  2. std::function
  3. std::bind
  4. Scegliere i callable
← Torna a C++ Academy