Generics en C++ : pourquoi les utiliser et comment
Bonjour, ami ! Si tu commences tout juste à apprendre le C++ et que tu as déjà rencontré le concept de Generics (ou templates), cet article est pour toi. Beaucoup de débutants ont peur des templates, les considérant comme quelque chose de complexe et de magique. En réalité, c'est bien plus simple. Comprenons ce que c'est, à quoi ça sert et comment les utiliser en pratique.
Que sont les Generics (templates) en C++ ?
Imagine que tu dois écrire une fonction qui additionne deux nombres. Tu écris une fonction pour int, une autre pour double, une troisième pour float… D'accord, c'est fastidieux et cela viole le principe DRY (Don't Repeat Yourself).
C'est là que les templates viennent à la rescousse. C'est un mécanisme qui permet d'écrire du code générique fonctionnant avec n'importe quel type de données. En C++, c'est l'équivalent de ce que d'autres langages appellent Generics (par exemple, en Java ou C#).
Un template n'est pas une fonction ou une classe concrète, mais un "plan" ou une "recette". Le compilateur, voyant que tu utilises un template avec le type int, crée une version du code pour int. Si tu l'utilises avec double, le compilateur crée une version pour double. Cela s'appelle l'instanciation du template.
Pourquoi les templates sont-ils utiles ? Trois raisons principales
1. Réutilisation du code
Au lieu d'écrire 10 fonctions pour différents types de nombres, tu en écris une seule universelle. Cela fait gagner du temps, réduit le nombre d'erreurs et rend le code plus lisible.
2. Sécurité des types
Contrairement aux macros (#define) ou à l'utilisation de void*, les templates sont vérifiés par le compilateur. Si tu essaies de passer un type inapproprié à un template, le compilateur générera une erreur à la compilation, et non à l'exécution du programme.
3. Performance
Les templates n'ajoutent pas de surcharge à l'exécution. Le compilateur crée un code optimisé pour chaque type spécifique, et ce code fonctionne aussi rapidement que si tu l'avais écrit manuellement.
Comment utiliser les templates : syntaxe et exemples
Examinons les deux principaux types de templates : les templates de fonctions et les templates de classes.
Templates de fonctions
L'exemple le plus simple est une fonction qui trouve le maximum de deux valeurs.
#include <iostream>#include <string>
// Déclaration du template de fonctiontemplate <typename T>T max_value(T a, T b) { return (a > b) ? a : b;}
int main() { // Fonctionne avec int std::cout << max_value(10, 20) << std::endl; // Sortie : 20 // Fonctionne avec double std::cout << max_value(3.14, 2.71) << std::endl; // Sortie : 3.14 // Fonctionne avec des chaînes std::cout << max_value(std::string("apple"), std::string("banana")) << std::endl; // Sortie : banana return 0;}Le mot-clé template indique au compilateur : "Attention, ce qui suit est un template". <typename T> est la liste des paramètres du template. T est un nom de type conditionnel qui sera remplacé par le type réel lors de l'appel de la fonction. Au lieu de typename, on peut utiliser class — il n'y a pas de différence.
Important : Le compilateur devine lui-même le type que vous voulez utiliser en fonction des arguments passés. Cela s'appelle la déduction des arguments du template. Mais vous pouvez spécifier le type explicitement :
std::cout << max_value<double>(10, 20.5) << std::endl; // Spécification explicite du type doubleTemplates de classes
Les templates de classes permettent de créer des conteneurs de données universels. Un exemple classique est un équivalent simple de std::pair.
#include <iostream>#include <string>
// Template