Menu
Coddy logo textTech

Specjalizacja szablonów

Część sekcji Programowanie obiektowe ścieżki C++ w Coddy. Lekcja 66 z 104.

Czasami ogólny szablon nie działa dobrze dla każdego typu. Na przykład porównanie ciągów znaków w stylu C za pomocą > porównuje adresy wskaźników, a nie rzeczywisty tekst. Specjalizacja szablonu pozwala podać niestandardową implementację dla określonych typów, zachowując ogólną wersję dla wszystkich pozostałych.

Pełna specjalizacja zastępuje cały szablon dla jednego określonego typu. Deklarujesz ją za pomocą pustej listy parametrów szablonu i określasz konkretny typ:

// Szablon główny
template <typename T>
class Printer {
public:
    void print(T value) {
        std::cout << value << std::endl;
    }
};

// Pełna specjalizacja dla 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);           // Wynik: 42

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

Szablony funkcji również można specjalizować:

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);              // Używa wersji ogólnej
isEqual("hi", "hi");        // Używa wersji wyspecjalizowanej

Kompilator zawsze wybiera najbardziej szczegółowe dopasowanie — jeśli istnieje specjalizacja dla dokładnie używanego typu, zostanie wybrana zamiast szablonu ogólnego.

challenge icon

Wyzwanie

Łatwy

Zbudujmy system formatowania świadomy typów, który pokazuje, jak specjalizacja szablonów pozwala dostosować zachowanie do konkretnych typów, zachowując jednocześnie ogólną wersję domyślną dla wszystkich pozostałych.

Utworzysz dwa pliki, aby uporządkować kod szablonów:

  • Formatter.h: Zdefiniuj szablon klasy o nazwie Formatter, który formatuje wartości do wyświetlenia. Ogólny szablon powinien działać z dowolnym typem, ale utworzysz też wyspecjalizowane wersje dla typów wymagających niestandardowej obsługi.

    Podstawowy szablon Formatter powinien zawierać:

    • Metodę format(), która przyjmuje wartość typu T i wyświetla: Value: <value>

    Utwórz pełną specjalizację dla bool, która wyświetla czytelny dla człowieka tekst zamiast 1 lub 0:

    • Metoda format() powinna wyświetlać: Boolean: true lub Boolean: false

    Utwórz pełną specjalizację dla const char*, która dodaje cudzysłowy wokół ciągów znaków:

    • Metoda format() powinna wyświetlać: String: "<value>"

    Utwórz również szablon funkcji o nazwie formatPair, który przyjmuje dwie wartości tego samego typu i wyświetla je razem w formacie: Pair: [<first>, <second>]

    Utwórz specjalizację formatPair dla const char*, która ujmuje każdy ciąg znaków w cudzysłowy: Pair: ["<first>", "<second>"]

  • main.cpp: Wczytaj cztery dane wejściowe (każdą w osobnym wierszu):
    1. Liczbę całkowitą
    2. Liczbę typu double
    3. Wartość logiczną jako ciąg znaków (true lub false)
    4. Wartość tekstową

    Zademonstruj działanie formaterów, tworząc odpowiednie obiekty Formatter i wywołując format() dla każdego typu:

    1. Sformatuj liczbę całkowitą za pomocą Formatter<int>
    2. Sformatuj liczbę typu double za pomocą Formatter<double>
    3. Sformatuj wartość logiczną za pomocą Formatter<bool> (najpierw przekształć wejściowy ciąg znaków na wartość bool)
    4. Sformatuj ciąg znaków za pomocą Formatter<const char*>

    Następnie zademonstruj specjalizację szablonu funkcji:

    1. Wywołaj formatPair z dwiema liczbami całkowitymi: 10 i 20
    2. Wywołaj formatPair z dwoma ciągami C: "hello" i "world"

Na przykład dla danych wejściowych 42, 3.14, true i Hello:

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

Zwróć uwagę, że ogólny szablon obsługuje liczby całkowite i liczby typu double w identyczny sposób, podczas gdy wyspecjalizowane wersje dla bool i const char* zapewniają niestandardowe formatowanie. Kompilator automatycznie wybiera najbardziej szczegółowe dopasowanie dla każdego użytego typu.

Spróbuj swoich sił

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

using namespace std;

int main() {
    // Wczytaj dane wejściowe
    int intVal;
    double doubleVal;
    string boolStr;
    string strVal;
    
    cin >> intVal;
    cin >> doubleVal;
    cin >> boolStr;
    cin >> strVal;
    
    // Przekonwertuj ciąg znaków na bool
    bool boolVal = (boolStr == "true");
    
    // TODO: Utwórz Formatter<int> i sformatuj liczbę całkowitą
    
    // TODO: Utwórz Formatter<double> i sformatuj liczbę typu double
    
    // TODO: Utwórz Formatter<bool> i sformatuj wartość logiczną
    
    // TODO: Utwórz Formatter<const char*> i sformatuj ciąg znaków
    // Wskazówka: Użyj strVal.c_str(), aby uzyskać const char*
    
    // TODO: Wywołaj formatPair z dwiema liczbami całkowitymi: 10 i 20
    
    // TODO: Wywołaj formatPair z dwoma ciągami znaków typu C: "hello" i "world"
    
    return 0;
}
quiz iconSprawdź się

Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.

Wszystkie lekcje w sekcji Programowanie obiektowe

Poćwicz samodzielnie: Kompilator C++ online