Menu
Coddy logo textTech

Templates variadiques

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

Que faire si vous avez besoin d’une fonction qui accepte un nombre quelconque d’arguments de n’importe quels types ? Les modèles traditionnels vous obligent à spécifier exactement le nombre de paramètres de type dont vous avez besoin. Les modèles variadiques résolvent ce problème en permettant aux modèles d’accepter un nombre arbitraire d’arguments de modèle.

La syntaxe utilise ... (points de suspension) pour créer un paquet de paramètres :

template <typename... Args>
void printAll(Args... args) {
    // Args est un pack de paramètres de template
    // args est un pack de paramètres de fonction
}

Pour traiter les arguments, on utilise généralement la récursivité avec un cas de base. Le paquet de paramètres se développe un argument à la fois jusqu'à ce qu'il n'en reste aucun :

// Cas de base : plus d'arguments restants
void print() {
    std::cout << std::endl;
}

// Cas récursif : traiter le premier argument, récursivité avec le reste
template <typename T, typename... Rest>
void print(T first, Rest... rest) {
    std::cout << first << " ";
    print(rest...);  // Développer les arguments restants
}

print(1, 3.14, "hello", 'x');  // Sortie : 1 3.14 hello x

Vous pouvez également utiliser les expressions de repli (C++17) pour des opérations plus simples, sans récursion explicite :

template <typename... Args>
auto sum(Args... args) {
    return (args + ...);  // Expression de fold : ajoute tous les arguments
}

std::cout << sum(1, 2, 3, 4) << std::endl;  // Sortie : 10

Les modèles variadiques sont à la base de nombreuses fonctionnalités de la bibliothèque standard, telles que std::make_unique, std::tuple et std::function. Ils permettent de créer des fonctions sûres du point de vue des types, qui fonctionnent avec n’importe quelle combinaison de types et de nombres d’arguments.

challenge icon

Défi

Facile

Construisons un système de journalisation flexible qui utilise des modèles variadiques pour gérer des messages comportant un nombre quelconque d’arguments. Vous créerez des utilitaires capables de concaténer des valeurs, de compter les arguments et d’afficher un résultat formaté, le tout à l’aide de packs de paramètres.

Vous organiserez votre code sur deux fichiers :

  • Variadic.h : définissez ici vos fonctions de modèles variadiques.

    Créez une fonction printAll qui affiche tous ses arguments séparés par des espaces, suivis d’un retour à la ligne. Utilisez l’approche récursive avec un cas de base qui affiche uniquement un retour à la ligne, et un cas récursif qui affiche le premier argument, un espace, puis effectue une récursion avec les arguments restants.

    Créez une fonction countArgs qui renvoie le nombre d’arguments qui lui sont transmis. Utilisez sizeof... pour obtenir la taille du pack de paramètres.

    Créez une fonction sum qui additionne tous les arguments numériques et renvoie le résultat. Utilisez une expression de réduction avec l’opérateur +.

    Créez une fonction product qui multiplie tous les arguments numériques et renvoie le résultat. Utilisez une expression de réduction avec l’opérateur *.

  • main.cpp : lisez quatre entrées (chacune sur une ligne distincte) :
    1. Un entier
    2. Un nombre à virgule flottante de type double
    3. Une chaîne de caractères
    4. Un caractère

    Démontrez vos modèles variadiques en :

    1. Appelant printAll avec les quatre entrées et en affichant le résultat
    2. Affichant le nombre d’arguments lors de l’appel de countArgs avec l’entier, le nombre à virgule flottante et le caractère : Argument count: <count>
    3. Calculant la somme de l’entier, du nombre à virgule flottante et des valeurs 10 et 5, puis en affichant : Sum: <result>
    4. Calculant le produit de l’entier et des valeurs 2 et 3, puis en affichant : Product: <result>
    5. Appelant printAll avec uniquement la chaîne de caractères (un seul argument)
    6. Appelant printAll sans argument (doit afficher uniquement un retour à la ligne)

Par exemple, avec les entrées 5, 2.5, Hello et X :

5 2.5 Hello X 
Argument count: 3
Sum: 22.5
Product: 30
Hello 

Remarquez comment printAll gère un nombre quelconque d’arguments de types mixtes, de quatre arguments à zéro. Les fonctions sum et product utilisent des expressions de réduction pour combiner élégamment toutes les valeurs sans récursion explicite. Votre fonction countArgs montre comment sizeof... vous donne la taille du pack au moment de la compilation.

Essayez vous-même

#include <iostream>
#include <string>
#include "Variadic.h"

using namespace std;

int main() {
    // Lire les entrées
    int intVal;
    double doubleVal;
    string strVal;
    char charVal;
    
    cin >> intVal;
    cin >> doubleVal;
    cin >> strVal;
    cin >> charVal;
    
    // TODO: Appeler printAll avec les quatre entrées
    
    // TODO: Print argument count using countArgs with intVal, doubleVal, and charVal
    // Format: "Argument count: <count>"
    
    // TODO: Calculer et afficher la somme de intVal, doubleVal, 10 et 5
    // Format : "Sum: <result>"
    
    // TODO: Calculer et afficher le produit de intVal, 2 et 3
    // Format : "Product: <result>"
    
    // TODO: Appeler printAll avec seulement la chaîne
    
    // TODO: Appeler printAll sans arguments
    
    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

Entraînez-vous par vous-même : Compilateur C++ en ligne