Menu
Coddy logo textTech

Templates de fonctions

Fait partie de la section Programmation Orientée Objet du Journey C++ de Coddy — leçon 64 sur 104.

Imaginez que vous écriviez une fonction pour trouver le maximum de deux entiers, puis que vous réalisiez que vous avez besoin de la même logique pour des doubles, et encore une fois pour des chaînes de caractères. Sans les templates, vous devriez écrire des fonctions presque identiques pour chaque type. Les templates de fonctions résolvent ce problème en vous permettant d'écrire la logique une seule fois et de laisser le compilateur générer automatiquement des versions spécifiques à chaque type.

Un modèle de fonction utilise le mot-clé template suivi des paramètres de modèle entre chevrons :

template <typename T>
T maximum(T a, T b) {
    return (a > b) ? a : b;
}

int main() {
    std::cout << maximum(5, 3) << std::endl;       // Utilise la version int
    std::cout << maximum(3.14, 2.71) << std::endl; // Utilise la version double
    std::cout << maximum('a', 'z') << std::endl;   // Utilise la version char
}

Le compilateur examine chaque appel et génère une fonction concrète pour ce type spécifique. Ce processus est appelé instanciation de modèle. Vous pouvez également spécifier explicitement le type si nécessaire :

std::cout << maximum<double>(5, 3.14) << std::endl;  // Force la version double

Les templates peuvent avoir plusieurs paramètres de type, permettant des conceptions encore plus flexibles :

template <typename T, typename U>
void printPair(T first, U second) {
    std::cout << first << ", " << second << std::endl;
}

printPair(42, "hello");    // T=int, U=const char*
printPair(3.14, 100);      // T=double, U=int

Les templates de fonctions fournissent un polymorphisme à la compilation — le type est déterminé lors de la compilation du code, et non à l'exécution. Cela signifie un surcoût nul à l'exécution par rapport aux fonctions virtuelles, ce qui rend les templates idéaux pour le code générique où la performance est critique.

challenge icon

Défi

Facile

Construisons une boîte à outils utilitaire en utilisant des modèles de fonctions pour créer des opérations réutilisables qui fonctionnent avec n'importe quel type compatible. Vous organiserez vos fonctions génériques dans un fichier d'en-tête et démontrerez leur flexibilité dans votre programme principal.

Vous allez créer deux fichiers :

  • MathUtils.h : Définissez une collection de modèles de fonctions qui effectuent des opérations courantes :

    minimum — une fonction modèle qui prend deux valeurs du même type et renvoie la plus petite.

    clamp — une fonction modèle qui prend trois paramètres : une valeur, une borne inférieure et une borne supérieure. Elle renvoie la valeur contrainte dans les bornes (renvoie la borne inférieure si la valeur est inférieure à celle-ci, la borne supérieure si la valeur est supérieure à celle-ci, sinon renvoie la valeur elle-même).

    swapValues — une fonction modèle qui prend deux références du même type et échange leurs valeurs.

  • main.cpp : Lisez six entrées (chacune sur une ligne séparée) :

    1. Premier entier
    2. Deuxième entier
    3. Une valeur double à limiter (clamp)
    4. Borne inférieure (double)
    5. Borne supérieure (double)
    6. Un caractère

    Démontrez vos modèles en :

    1. Trouvant le minimum des deux entiers et en affichant : Min of <a> and <b>: <result>
    2. Trouvant le minimum entre le caractère 'm' et votre caractère d'entrée, en affichant : Min of m and <char>: <result>
    3. Limitant (clamping) la valeur double et en affichant : Clamp <value> to [<low>, <high>]: <result>
    4. Limitant le premier entier à l'intervalle [0, 100] et en affichant : Clamp <value> to [0, 100]: <result>
    5. Échangeant les deux entiers et en affichant : After swapValues: <a>, <b>

Par exemple, avec les entrées 25, 10, 3.7, 1.0, 5.0, et z :

Min of 25 and 10: 10
Min of m and z: m
Clamp 3.7 to [1, 5]: 3.7
Clamp 25 to [0, 100]: 25
After swapValues: 10, 25

Remarquez comment chaque fonction modèle fonctionne parfaitement avec des entiers, des doubles et des caractères — le compilateur génère la version appropriée pour chaque type que vous utilisez. Votre fonction swapValues doit modifier les variables originales via des références, démontrant que les modèles fonctionnent avec des paramètres de référence tout comme les fonctions régulières.

Aide-mémoire

Les modèles de fonctions vous permettent d'écrire des fonctions génériques qui fonctionnent avec plusieurs types. Utilisez le mot-clé template suivi des paramètres de modèle :

template <typename T>
T maximum(T a, T b) {
    return (a > b) ? a : b;
}

Le compilateur génère automatiquement des versions spécifiques aux types via l'instanciation de modèle :

maximum(5, 3);        // Génère la version int
maximum(3.14, 2.71);  // Génère la version double
maximum('a', 'z');    // Génère la version char

Vous pouvez spécifier explicitement le type si nécessaire :

maximum<double>(5, 3.14);  // Force la version double

Les modèles prennent en charge plusieurs paramètres de type :

template <typename T, typename U>
void printPair(T first, U second) {
    std::cout << first << ", " << second << std::endl;
}

printPair(42, "hello");  // T=int, U=const char*

Les modèles fonctionnent avec des paramètres par référence pour modifier les valeurs d'origine :

template <typename T>
void swapValues(T& a, T& b) {
    T temp = a;
    a = b;
    b = temp;
}

Les modèles de fonctions offrent un polymorphisme à la compilation avec une surcharge nulle à l'exécution, ce qui les rend idéaux pour le code générique critique en termes de performances.

Essayez vous-même

#include <iostream>
#include "MathUtils.h"
using namespace std;

int main() {
    // Lire les entrées
    int a, b;
    double value, low, high;
    char ch;
    
    cin >> a;
    cin >> b;
    cin >> value;
    cin >> low;
    cin >> high;
    cin >> ch;
    
    // TODO: Utiliser le template minimum pour trouver le min de deux entiers
    // Afficher : "Min of <a> and <b>: <result>"
    
    // TODO: Utiliser le template minimum pour trouver le min de 'm' et du caractère saisi
    // Afficher : "Min of m and <char>: <result>"
    
    // TODO: Utiliser le template clamp sur la valeur double
    // Afficher : "Clamp <value> to [<low>, <high>]: <result>"
    
    // TODO: Utiliser le template clamp sur le premier entier avec la plage [0, 100]
    // Afficher : "Clamp <value> to [0, 100]: <result>"
    
    // TODO: Utiliser le template swapValues sur les deux entiers
    // Afficher : "After swapValues: <a>, <b>"
    
    return 0;
}
quiz iconTestez-vous

Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.

Toutes les leçons de Programmation Orientée Objet