Menu
Coddy logo textTech

Template-Spezialisierung

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

Manchmal funktioniert ein generisches Template nicht gut für jeden Typ. Zum Beispiel vergleicht der Vergleich von C-Strings mit > Zeigeradressen und nicht den tatsächlichen Text. Eine Templatespezialisierung ermöglicht es dir, eine benutzerdefinierte implementation für bestimmte Typen bereitzustellen und gleichzeitig die generische Version für alles andere beizubehalten.

Eine full-Spezialisierung ersetzt das gesamte Template für einen bestimmten Typ. Du deklarierst sie mit einer leeren Template-Parameterliste und gibst den konkreten Typ an:

// Primäres Template
template <typename T>
class Printer {
public:
    void print(T value) {
        std::cout << value << std::endl;
    }
};

// Vollständige Spezialisierung für const char*
template <>
class Printer<const char*> {
public:
    void print(const char* value) {
        std::cout << "String: " << value << std::endl;
    }
};

Printer<int> intPrinter;
intPrinter.print(42);           // Ausgabe: 42

Printer<const char*> strPrinter;
strPrinter.print("hello");      // Ausgabe: String: hello

Funktionsvorlagen können ebenfalls spezialisiert werden:

template <typename T>
bool isEqual(T a, T b) {
    return a == b;
}

template <>
bool isEqual<const char*>(const char* a, const char* b) {
    return std::strcmp(a, b) == 0;
}

isEqual(5, 5);              // Verwendet generische Version
isEqual("hi", "hi");        // Verwendet spezialisierte Version

Der Compiler bevorzugt immer die spezifischste Übereinstimmung – wenn eine Spezialisierung für den genau verwendeten Typ existiert, wird sie gegenüber der generischen Vorlage ausgewählt.

challenge icon

Aufgabe

Einfach

Lass uns ein typbewusstes Formatierungssystem erstellen, das zeigt, wie du mithilfe von Template-Spezialisierungen das Verhalten für bestimmte Typen anpassen kannst, während du für alle anderen Typen einen generischen Fallback beibehältst.

Du erstellst zwei Dateien, um deinen Template-Code zu organisieren:

  • Formatter.h: Definiere ein Klassen-Template namens Formatter, das Werte für die Anzeige formatiert. Dein generisches Template sollte mit jedem Typ funktionieren, aber du erstellst außerdem spezialisierte Versionen für Typen, die eine benutzerdefinierte Behandlung benötigen.

    Das primäre Formatter-Template sollte Folgendes enthalten:

    • Eine format()-Methode, die einen Wert vom Typ T entgegennimmt und Folgendes ausgibt: Value: <value>

    Erstelle eine vollständige Spezialisierung für bool, die menschenlesbaren Text anstelle von 1 oder 0 ausgibt:

    • Die format()-Methode sollte Folgendes ausgeben: Boolean: true oder Boolean: false

    Erstelle eine vollständige Spezialisierung für const char*, die Zeichenketten in Anführungszeichen setzt:

    • Die format()-Methode sollte Folgendes ausgeben: String: "<value>"

    Erstelle außerdem ein Funktions-Template namens formatPair, das zwei Werte desselben Typs entgegennimmt und sie gemeinsam wie folgt ausgibt: Pair: [<first>, <second>]

    Erstelle eine Spezialisierung von formatPair für const char*, die jede Zeichenkette in Anführungszeichen setzt: Pair: ["<first>", "<second>"]

  • main.cpp: Lies vier Eingaben ein (jeweils in einer eigenen Zeile):
    1. Eine Ganzzahl
    2. Eine Gleitkommazahl
    3. Einen booleschen Wert als Zeichenkette (true oder false)
    4. Einen Zeichenkettenwert

    Führe deine Formatter vor, indem du passende Formatter-Objekte erstellst und für jeden Typ format() aufrufst:

    1. Formatiere die Ganzzahl mit Formatter<int>
    2. Formatiere die Gleitkommazahl mit Formatter<double>
    3. Formatiere den booleschen Wert mit Formatter<bool> (wandle zuerst die Zeichenketteneingabe in einen booleschen Wert um)
    4. Formatiere die Zeichenkette mit Formatter<const char*>

    Führe anschließend die Spezialisierung des Funktions-Templates vor:

    1. Rufe formatPair mit zwei Ganzzahlen auf: 10 und 20
    2. Rufe formatPair mit zwei C-Zeichenketten auf: "hello" und "world"

Beispielsweise mit den Eingaben 42, 3.14, true und Hello:

Value: 42
Value: 3.14
Boolean: true
String: "Hello"
Pair: [10, 20]
Pair: ["hello", "world"]

Beachte, wie das generische Template Ganzzahlen und Gleitkommazahlen identisch verarbeitet, während die spezialisierten Versionen für bool und const char* eine benutzerdefinierte Formatierung bereitstellen. Der Compiler wählt automatisch für jeden verwendeten Typ die spezifischste passende Variante aus.

Probier es selbst

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

using namespace std;

int main() {
    // Eingaben lesen
    int intVal;
    double doubleVal;
    string boolStr;
    string strVal;
    
    cin >> intVal;
    cin >> doubleVal;
    cin >> boolStr;
    cin >> strVal;
    
    // String in bool umwandeln
    bool boolVal = (boolStr == "true");
    
    // TODO: Formatter<int> erstellen und die Ganzzahl formatieren
    
    // TODO: Formatter<double> erstellen und den Double formatieren
    
    // TODO: Formatter<bool> erstellen und den Boolean formatieren
    
    // TODO: Formatter<const char*> erstellen und den String formatieren
    // Hinweis: Verwende strVal.c_str(), um const char* zu erhalten
    
    // TODO: formatPair mit zwei Ganzzahlen aufrufen: 10 und 20
    
    // TODO: formatPair mit zwei C-Strings aufrufen: "hello" und "world"
    
    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