Menu
Coddy logo textTech

Variadische Templates

Teil des Abschnitts Objektorientierte Programmierung der C++-Journey von Coddy. Lektion 67 von 104.

Was ist, wenn du eine Funktion benötigst, die eine beliebige Anzahl von Argumenten beliebiger Typen akzeptiert? Herkömmliche Templates erfordern, dass du genau angibst, wie viele Typparameter du benötigst. Variadische Templates lösen dieses Problem, indem sie Templates ermöglichen, eine beliebige Anzahl von Template-Argumenten zu akzeptieren.

Die Syntax verwendet ... (Auslassungspunkte), um ein Parameterpaket zu erstellen:

template <typename... Args>
void printAll(Args... args) {
    // Args ist ein Template-Parameterpack
    // args ist ein Funktionsparameterpack
}

Um die Argumente zu verarbeiten, verwendest du typischerweise Rekursion mit einem Basisfall. Das Parameterpaket wird jeweils um ein Argument erweitert, bis keine Argumente mehr übrig sind:

// Basisfall: keine Argumente übrig
void print() {
    std::cout << std::endl;
}

// Rekursiver Fall: erstes Argument verarbeiten, mit dem Rest rekursieren
template <typename T, typename... Rest>
void print(T first, Rest... rest) {
    std::cout << first << " ";
    print(rest...);  // Verbleibende Argumente expandieren
}

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

Du kannst auch Fold-Ausdrücke (C++17) für einfachere Operationen ohne explizite Rekursion verwenden:

template <typename... Args>
auto sum(Args... args) {
    return (args + ...);  // Fold-Expression: addiert alle Argumente
}

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

Variadische Templates bilden die Grundlage für viele Funktionen der Standardbibliothek wie std::make_unique, std::tuple und std::function. Sie ermöglichen typsichere Funktionen, die mit jeder Kombination von Argumenttypen und -anzahlen funktionieren.

challenge icon

Aufgabe

Einfach

Erstelle ein flexibles Protokollierungssystem, das Variadic Templates verwendet, um Nachrichten mit beliebig vielen Argumenten zu verarbeiten. Du erstellst Hilfsfunktionen, die Werte verketten, Argumente zählen und formatierte Ausgaben erzeugen – alles mithilfe von Parameter-Packs.

Du organisierst deinen Code über zwei Dateien:

  • Variadic.h: Definiere hier deine Variadic-Template-Funktionen.

    Erstelle eine printAll-Funktion, die alle ihre Argumente durch Leerzeichen getrennt ausgibt, gefolgt von einem Zeilenumbruch. Verwende den rekursiven Ansatz mit einem Basisfall, der lediglich einen Zeilenumbruch ausgibt, und einem rekursiven Fall, der das erste Argument, ein Leerzeichen und anschließend den rekursiven Aufruf mit den verbleibenden Argumenten ausgibt.

    Erstelle eine countArgs-Funktion, die die Anzahl der an sie übergebenen Argumente zurückgibt. Verwende sizeof..., um die Größe des Parameter-Packs zu ermitteln.

    Erstelle eine sum-Funktion, die alle numerischen Argumente addiert und das Ergebnis zurückgibt. Verwende einen Fold-Ausdruck mit dem Operator +.

    Erstelle eine product-Funktion, die alle numerischen Argumente multipliziert und das Ergebnis zurückgibt. Verwende einen Fold-Ausdruck mit dem Operator *.

  • main.cpp: Lies vier Eingaben ein (jede in einer eigenen Zeile):
    1. Eine Ganzzahl
    2. Eine Gleitkommazahl vom Typ double
    3. Eine Zeichenkette
    4. Ein Zeichen

    Demonstriere deine Variadic Templates durch:

    1. Aufrufen von printAll mit allen vier Eingaben und Ausgeben des Ergebnisses
    2. Ausgeben der Anzahl der Argumente beim Aufruf von countArgs mit der Ganzzahl, der Gleitkommazahl und dem Zeichen: Argument count: <count>
    3. Berechnen der Summe aus der Ganzzahl, der Gleitkommazahl sowie den Werten 10 und 5 und anschließendes Ausgeben von: Sum: <result>
    4. Berechnen des Produkts aus der Ganzzahl und den Werten 2 und 3 und anschließendes Ausgeben von: Product: <result>
    5. Aufrufen von printAll nur mit der Zeichenkette (ein einzelnes Argument)
    6. Aufrufen von printAll ohne Argumente (soll lediglich einen Zeilenumbruch ausgeben)

Bei den Eingaben 5, 2.5, Hello und X sieht die Ausgabe beispielsweise so aus:

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

Beachte, wie printAll eine beliebige Anzahl von Argumenten unterschiedlichen Typs verarbeitet – von vier Argumenten bis hin zu null. Die Funktionen sum und product verwenden Fold-Ausdrücke, um alle Werte elegant zu kombinieren, ohne eine explizite Rekursion zu benötigen. Deine countArgs-Funktion zeigt, wie sizeof... die Größe des Packs zur Kompilierzeit liefert.

Probier es selbst

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

using namespace std;

int main() {
    // Eingaben lesen
    int intVal;
    double doubleVal;
    string strVal;
    char charVal;
    
    cin >> intVal;
    cin >> doubleVal;
    cin >> strVal;
    cin >> charVal;
    
    // TODO: Rufe printAll mit allen vier Eingaben auf
    
    // TODO: Print argument count using countArgs with intVal, doubleVal, and charVal
    // Format: "Argument count: <count>"
    
    // TODO: Berechne und gib die Summe von intVal, doubleVal, 10 und 5 aus
    // Format: "Sum: <result>"
    
    // TODO: Berechne und gib das Produkt von intVal, 2 und 3 aus
    // Format: "Product: <result>"
    
    // TODO: Rufe printAll nur mit dem String auf
    
    // TODO: Rufe printAll ohne Argumente auf
    
    return 0;
}
quiz iconTeste dich selbst

Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.

Alle Lektionen in Objektorientierte Programmierung

Übe selbstständig: Online-C++-Compiler