Menu
Coddy logo textTech

Template-Spezialisierung

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

Manchmal funktioniert eine generische Vorlage nicht gut für jeden Typ. Zum Beispiel vergleicht das Vergleichen von C-Strings mit > Zeigeradressen und nicht den eigentlichen Text. Die Templatespezialisierung ermöglicht es dir, eine benutzerdefinierte Implementierung für bestimmte Typen bereitzustellen und gleichzeitig die generische Version für alles andere beizubehalten.

Eine vollständige 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

Erstellen wir ein typsicheres Formatierungssystem, das zeigt, wie die Template-Spezialisierung das Anpassen des Verhaltens für bestimmte Typen ermöglicht und gleichzeitig für alle anderen Typen eine generische Standardimplementierung beibehält.

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

  • Formatter.h: Definiere ein Klassentemplate namens Formatter, das Werte zur Anzeige formatiert. Dein generisches Template sollte mit jedem Typ funktionieren. Zusätzlich erstellst du 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 übernimmt und Folgendes ausgibt: Value: <value>

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

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

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

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

    Erstelle außerdem ein Funktionstemplate namens formatPair, das zwei Werte desselben Typs übernimmt und sie zusammen als Pair: [<first>, <second>] ausgibt.

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

  • main.cpp: Lies vier Eingaben ein, jeweils in einer eigenen Zeile:
    1. Eine Ganzzahl
    2. Eine Gleitkommazahl vom Typ double
    3. Einen booleschen Wert als Zeichenfolge (true oder false)
    4. Einen Zeichenfolgenwert

    Demonstriere deine Formatierer, 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 die Eingabezeichenfolge zuerst in einen booleschen Wert um)
    4. Formatiere die Zeichenfolge mit Formatter<const char*>

    Demonstriere anschließend die Spezialisierung des Funktionstemplates:

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

Bei den Eingaben 42, 3.14, true und Hello sieht die Ausgabe beispielsweise so aus:

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

Beachte, wie das generische Template Ganzzahlen und Gleitkommazahlen identisch behandelt, 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 Version 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