0Pricing
C++ Academy · Leçon

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* ou const 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

  1. Spécialisation complète
  2. Spécialisation partielle
  3. SFINAE
  4. Schémas avec enable_if
← Retour à C++ Academy