0Pricing
C++ Academy · Lezione

Pattern con enable_if

Vincolare i template nel modo classico

Pattern con enable_if è 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.

Che cos'è enable_if?

std::enable_if è un piccolo trait che definisce condizionalmente un membro type. Quando la condizione è vera, il tipo esiste; quando è falsa, il template circostante viene rimosso tramite SFINAE.

  • Si trova in <type_traits>.
  • È lo strumento classico per vincolare i template.
#include <iostream>
#include <type_traits>

template <typename T>
typename std::enable_if<std::is_integral<T>::value, T>::type
doubleIt(T v) { return v * 2; }

int main() {
    std::cout << doubleIt(21) << '\n';
    return 0;
}

Come funziona

enable_if<Cond, T>::type è T solo quando Cond è vera. Se è falsa, non esiste alcun membro type, quindi la sostituzione non riesce.

#include <iostream>
#include <type_traits>

int main() {
    std::cout << std::boolalpha;
    std::cout << std::is_same<std::enable_if<true, int>::type, int>::value << '\n';
    return 0;
}

enable_if nel tipo restituito

La posizione più comune è il tipo restituito. La funzione esiste solo quando la condizione è soddisfatta.

#include <iostream>
#include <type_traits>

template <typename T>
typename std::enable_if<std::is_floating_point<T>::value, T>::type
half(T v) { return v / 2; }

int main() {
    std::cout << half(5.0) << '\n';
    return 0;
}

enable_if come parametro di template

Un altro schema inserisce enable_if in un parametro di template con valore predefinito, mantenendo pulito il tipo restituito.

#include <iostream>
#include <type_traits>

template <typename T, typename = typename std::enable_if<std::is_integral<T>::value>::type>
T triple(T v) { return v * 3; }

int main() {
    std::cout << triple(4) << '\n';
    return 0;
}

La scorciatoia enable_if_t

C++14 ha aggiunto l'alias std::enable_if_t<Cond, T>, così è possibile evitare la verbosità di typename ...::type.

#include <iostream>
#include <type_traits>

template <typename T>
std::enable_if_t<std::is_integral<T>::value, T>
negate(T v) { return -v; }

int main() {
    std::cout << negate(8) << '\n';
    return 0;
}

Affiancare due overload

Si definiscono condizioni complementari in modo che esattamente un overload sia valido per ogni tipo, senza ambiguità.

#include <iostream>
#include <type_traits>

template <typename T>
std::enable_if_t<std::is_integral<T>::value, const char*>
category() { return "integer"; }

template <typename T>
std::enable_if_t<!std::is_integral<T>::value, const char*>
category() { return "non-integer"; }

int main() {
    std::cout << category<int>() << ' ' << category<double>() << '\n';
    return 0;
}

Combinare le condizioni

Si usano operatori logici sui valori dei trait per esprimere vincoli più ricchi, come "integrale e con segno".

#include <iostream>
#include <type_traits>

template <typename T>
std::enable_if_t<std::is_integral<T>::value && std::is_signed<T>::value, T>
magnitude(T v) { return v < 0 ? -v : v; }

int main() {
    std::cout << magnitude(-12) << '\n';
    return 0;
}

Vincolare un costruttore

È possibile inserire enable_if nel parametro di template di un costruttore per consentirne l'uso solo con tipi compatibili.

#include <iostream>
#include <type_traits>

struct Wrapper {
    int value;
    template <typename T, typename = std::enable_if_t<std::is_integral<T>::value>>
    Wrapper(T v) : value(static_cast<int>(v)) {}
};

int main() {
    Wrapper w(42);
    std::cout << w.value << '\n';
    return 0;
}

Insidia dell'argomento predefinito del template

Due overload che differiscono solo per un parametro di template enable_if con valore predefinito vengono considerati ridefinizioni. È necessario dare loro forme diverse (ad esempio, inserendo una delle condizioni nel tipo restituito).

#include <iostream>
#include <type_traits>

template <typename T>
std::enable_if_t<std::is_integral<T>::value, void>
printKind() { std::cout << "int\n"; }

template <typename T>
std::enable_if_t<std::is_floating_point<T>::value, void>
printKind() { std::cout << "float\n"; }

int main() {
    printKind<int>();
    printKind<double>();
    return 0;
}

Confronto con i concepts

I concepts di C++20 sostituiscono la maggior parte degli usi di enable_if con una sintassi molto più chiara, ma enable_if resta essenziale per il codice precedente a C++20 e per alcuni casi limite.

#include <iostream>
#include <type_traits>

template <typename T>
std::enable_if_t<std::is_arithmetic<T>::value, T>
square(T v) { return v * v; }

int main() {
    std::cout << square(6) << ' ' << square(1.5) << '\n';
    return 0;
}

Un esempio completo

Si combinano tutti gli elementi: una famiglia di funzioni che formatta in modo diverso interi e numeri in virgola mobile, con selezione a tempo di compilazione.

#include <iostream>
#include <type_traits>

template <typename T>
std::enable_if_t<std::is_integral<T>::value, void>
format(T v) { std::cout << "int[" << v << "]\n"; }

template <typename T>
std::enable_if_t<std::is_floating_point<T>::value, void>
format(T v) { std::cout << "float(" << v << ")\n"; }

int main() {
    format(10);
    format(3.5);
    return 0;
}

Verifica rapida

Verifichi la Sua comprensione di enable_if.

Riepilogo

Ha imparato a conoscere i pattern classici di enable_if:

  • definisce ::type solo quando la condizione è vera, abilitando la SFINAE
  • viene inserito nel tipo restituito o in un parametro di template con valore predefinito
  • si usa l'alias enable_if_t e si combinano i trait con operatori logici
  • i concepts lo hanno superato in C++20, ma resta ampiamente utilizzato

Il corso sulla specializzazione dei template e sulla SFINAE è completo.

Domande Frequenti

La lezione «Pattern con enable_if» è gratuita?

Sì — il testo completo di «Pattern con enable_if» è 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 «Pattern con enable_if»?

Vincolare i template nel modo classico 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 «Pattern con enable_if»?

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. Specializzazione completa
  2. Specializzazione parziale
  3. SFINAE
  4. Pattern con enable_if
← Torna a C++ Academy