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
::typesolo 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_te 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
- Specializzazione completa
- Specializzazione parziale
- SFINAE
- Pattern con enable_if