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 doubleLes 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=intLes 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.
Défi
FacileConstruisons 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) :- Premier entier
- Deuxième entier
- Une valeur double à limiter (clamp)
- Borne inférieure (double)
- Borne supérieure (double)
- Un caractère
Démontrez vos modèles en :
- Trouvant le minimum des deux entiers et en affichant :
Min of <a> and <b>: <result> - Trouvant le minimum entre le caractère
'm'et votre caractère d'entrée, en affichant :Min of m and <char>: <result> - Limitant (clamping) la valeur double et en affichant :
Clamp <value> to [<low>, <high>]: <result> - Limitant le premier entier à l'intervalle [0, 100] et en affichant :
Clamp <value> to [0, 100]: <result> - É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, 25Remarquez 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 charVous pouvez spécifier explicitement le type si nécessaire :
maximum<double>(5, 3.14); // Force la version doubleLes 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;
}
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
1Fondamentaux de la POO
Fichiers externesBuild et Compilation C++Fichiers d'en-tête et Fichiers sourceEspaces de noms et PortéeIntroduction à la POO en C++Classes vs ObjetsLe pointeur 'this'Méthodes (Fonctions membres)Attributs (Membres de données)Bases des Ctors et DtorsRécapitulatif - Calculatrice simple4Propriétés de classe
Membres d'instance vs membres statiquesGetters et SettersFonctions membres constMot-clé mutableMéthodes et variables statiquesFonctions et classes amiesRécapitulatif - Gestionnaire de compte bancaire7Héritage
Héritage de baseNiveaux d'accès à l'héritageOrdre d'appel des Ctor et DtorRedéfinition de méthodesFonctions virtuelles et VTableHéritage multipleHéritage virtuelRécapitulatif - Hiérarchie des employés10Présentation de la STL
Présentation et philosophie de la STLConteneurs de la STLItérateursAlgorithmes de la STLFoncteurs et expressions lambdaRécapitulatif - Fréquence des mots13Patrons de conception, Partie 1
Introduction aux patrons de conceptionPatron SingletonFabrique & Fabrique abstraitePatron MonteurPatron ObservateurPatron Stratégie2Gestion de la mémoire
Mémoire Pile vs TasPointeurs et RéférencesMémoire dynamique (new/delete)Smart Pointers en C++RAII en C++Récapitulatif - Gestionnaire de tableaux dynamiques5Encapsulation
Spécificateurs d'accès en C++Spécificateurs d'accès en profondeurMasquage d'informationStruct vs ClassClasses imbriquées et internesRécapitulatif - Système de gestion d'étudiants8Polymorphisme
Polymorphisme : Compilation vs ExécutionSurcharge de fonctionsRetour sur les fonctions virtuellesFonctions virtuelles puresClasses abstraitesConception d'interfaces en C++Dynamic Casting & RTTIRécapitulatif - Calculateur de formes11Concepts avancés de la POO
Composition vs HéritageMixins via CRTPIdiome PimplEffacement de typeEnum Classes & Typage fortGestion des exceptions en POOHiérarchies d'exceptions personnalisées14Patrons de conception, Partie 2
Patron CommandePatron AdaptateurPatron DécorateurPatron Template MethodPatron ÉtatPatron CompositeRAII en tant que patron3Constructeurs et Destructeurs
Constructeur par défautConstructeur paramétréConstructeur de copieConstructeur de déplacementListes d'initialisation du constructeurConstructeurs déléguésAnalyse approfondie du destructeurRègle de trois / cinq / zéroRécapitulatif - Classe String6Surcharge d'opérateurs
Introduction à la surcharge d'opérateursSurcharge des opérateurs arithmétiquesSurcharge des opérateurs de comparaisonOpérateurs de fluxSurcharge de l'opérateur d'affectationSurcharge des opérateurs [] et ()Opérateurs de conversion de typeRécapitulatif - Classe Matrix9Templates
Templates de fonctionsTemplates de classesSpécialisation de templatesTemplates variadiquesBases de SFINAE & Type TraitsRécapitulatif - Conteneur générique