Spécialisation partielle
Spécialiser des motifs de modèles
Spécialisation partielle est une leçon C++ Academy gratuite sur CoddyKit. Ceci est la leçon 2 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage C++ Academy, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours C++ Academy comprend 4 leçons au total.
Qu’est-ce que la spécialisation partielle ?
La spécialisation partielle personnalise un modèle pour une famille de types partageant un motif, plutôt que pour un type précis.
- Seuls les modèles de classe la prennent en charge.
- Vous laissez certains paramètres génériques.
#include <iostream>
template <typename T>
struct Traits { static const char* kind() { return "value"; } };
template <typename T>
struct Traits<T*> { static const char* kind() { return "pointer"; } };
int main() {
std::cout << Traits<int>::kind() << '\n';
std::cout << Traits<int*>::kind() << '\n';
return 0;
}Correspondance des pointeurs
Le motif T* correspond à n’importe quel type pointeur, ce qui vous permet de gérer tous les pointeurs avec une seule spécialisation.
#include <iostream>
template <typename T>
struct Deref { static T get(T v) { return v; } };
template <typename T>
struct Deref<T*> { static T get(T* p) { return *p; } };
int main() {
int x = 42;
std::cout << Deref<int>::get(7) << '\n';
std::cout << Deref<int*>::get(&x) << '\n';
return 0;
}Les fonctions ne peuvent pas être spécialisées partiellement
Seuls les modèles de classe et de variable prennent en charge la spécialisation partielle. Pour les fonctions, vous utilisez plutôt la surcharge.
#include <iostream>
template <typename T>
void show(T) { std::cout << "value\n"; }
template <typename T>
void show(T*) { std::cout << "pointer\n"; }
int main() {
int x = 0;
show(5);
show(&x);
return 0;
}Spécialiser l’un des deux paramètres
Avec plusieurs paramètres de type, vous pouvez en fixer un et laisser l’autre ouvert, afin de faire correspondre un motif entre plusieurs types.
#include <iostream>
template <typename A, typename B>
struct Pair { static const char* kind() { return "mixed"; } };
template <typename A>
struct Pair<A, A> { static const char* kind() { return "same types"; } };
int main() {
std::cout << Pair<int, double>::kind() << '\n';
std::cout << Pair<int, int>::kind() << '\n';
return 0;
}Correspondance des tableaux
Vous pouvez faire correspondre les types tableau avec un motif qui capture le type des éléments et la taille comme paramètre non typé.
#include <iostream>
template <typename T>
struct Info { static int size() { return 1; } };
template <typename T, int N>
struct Info<T[N]> { static int size() { return N; } };
int main() {
std::cout << Info<int>::size() << '\n';
std::cout << Info<int[5]>::size() << '\n';
return 0;
}Motifs const
Une spécialisation peut supprimer ou détecter const en faisant correspondre const T comme motif.
#include <iostream>
template <typename T>
struct IsConst { static const bool value = false; };
template <typename T>
struct IsConst<const T> { static const bool value = true; };
int main() {
std::cout << std::boolalpha;
std::cout << IsConst<int>::value << '\n';
std::cout << IsConst<const int>::value << '\n';
return 0;
}La spécialisation la plus précise l’emporte
Lorsque plusieurs spécialisations peuvent correspondre, le compilateur choisit la plus spécialisée, c’est-à-dire le motif le plus précis.
#include <iostream>
template <typename T>
struct K { static int v() { return 0; } };
template <typename T>
struct K<T*> { static int v() { return 1; } };
template <>
struct K<int*> { static int v() { return 2; } };
int main() {
std::cout << K<double*>::v() << ' ' << K<int*>::v() << '\n';
return 0;
}Motifs de référence
Vous pouvez également faire correspondre les types référence, afin de distinguer une référence d’une valeur simple.
#include <iostream>
template <typename T>
struct Cat { static const char* k() { return "value"; } };
template <typename T>
struct Cat<T&> { static const char* k() { return "lvalue ref"; } };
int main() {
std::cout << Cat<int>::k() << '\n';
std::cout << Cat<int&>::k() << '\n';
return 0;
}Construire des traits de types
La spécialisation partielle est le mécanisme qui permet de construire les traits de types. Voici un remove_pointer écrit manuellement.
#include <iostream>
#include <type_traits>
template <typename T>
struct RemovePtr { using type = T; };
template <typename T>
struct RemovePtr<T*> { using type = T; };
int main() {
std::cout << std::boolalpha;
std::cout << std::is_same<RemovePtr<int*>::type, int>::value << '\n';
return 0;
}Combiner des motifs
Vous pouvez combiner des motifs, par exemple faire correspondre un pointeur vers une valeur constante, afin de gérer des structures de types imbriquées.
#include <iostream>
template <typename T>
struct Desc { static const char* k() { return "plain"; } };
template <typename T>
struct Desc<const T*> { static const char* k() { return "ptr to const"; } };
int main() {
std::cout << Desc<int>::k() << '\n';
std::cout << Desc<const int*>::k() << '\n';
return 0;
}Un trait pratique pour les conteneurs
Utilisez une spécialisation partielle pour extraire le type des éléments d’un modèle similaire à un conteneur.
#include <iostream>
#include <type_traits>
template <typename C>
struct Element { using type = void; };
template <template <typename> class C, typename T>
struct Element<C<T>> { using type = T; };
template <typename T>
struct Box { T item; };
int main() {
std::cout << std::boolalpha;
std::cout << std::is_same<Element<Box<int>>::type, int>::value << '\n';
return 0;
}Vérification rapide
Vérifiez votre compréhension de la spécialisation partielle.
Récapitulatif
Vous avez découvert la spécialisation partielle :
- elle personnalise un modèle de classe pour un motif de types comme
T*ouconst T - les fonctions utilisent la surcharge, et non la spécialisation partielle
- la version correspondante la plus spécialisée est sélectionnée
- elle est à la base de traits de types tels que
remove_pointer
Vous allez maintenant découvrir SFINAE, une technique qui permet d’activer des fonctions uniquement lorsqu’un type répond aux critères requis.
Questions Fréquemment Posées
La leçon « Spécialisation partielle » est-elle gratuite ?
Oui — le texte complet de « Spécialisation partielle » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours C++ Academy, passe à CoddyKit PRO. Le cours C++ Academy comprend 4 leçons au total.
Qu'est-ce que j'apprendrai dans « Spécialisation partielle » ?
Spécialiser des motifs de modèles Tu pratiques C++ Academy avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.
Dois-je avoir de l'expérience pour commencer C++ Academy ?
Aucune expérience préalable n'est requise. C++ Academy sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 2 sur 4.
Combien de temps prend la leçon « Spécialisation partielle » ?
La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.
Peux-tu écrire et exécuter du code dans cette leçon C++ Academy ?
Oui. Chaque leçon C++ Academy inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.
Toutes les leçons de ce cours
- Spécialisation complète
- Spécialisation partielle
- SFINAE
- Schémas avec enable_if