Menu
Coddy logo textTech

Specializzazione dei template

Fa parte della sezione Programmazione orientata agli oggetti del percorso C++ di Coddy. Lezione 66 di 104.

A volte un modello generico non funziona bene per ogni tipo. Per esempio, confrontare stringhe in stile C con > confronta gli indirizzi dei puntatori, non il testo effettivo. La specializzazione del modello ti permette di fornire un’implementazione personalizzata per tipi specifici, mantenendo la versione generica per tutto il resto.

Una specializzazione completa sostituisce l'intero modello per un tipo specifico. La dichiari con un elenco di parametri del modello vuoto e specifichi il tipo concreto:

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

// Specializzazione completa per 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);           // Output: 42

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

Anche i modelli di funzione possono essere specializzati:

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);              // Usa la versione generica
isEqual("hi", "hi");        // Usa la versione specializzata

Il compilatore preferisce sempre la corrispondenza più specifica: se esiste una specializzazione per il tipo esatto utilizzato, verrà scelta al posto del modello generico.

challenge icon

Sfida

Facile

Costruiamo un sistema di formattazione consapevole del tipo che mostri come la specializzazione dei template consenta di personalizzare il comportamento per tipi specifici, mantenendo al contempo un fallback generico per tutto il resto.

Creerai due file per organizzare il codice dei template:

  • Formatter.h: definisci un template di classe chiamato Formatter che formatta i valori da visualizzare. Il template generico dovrebbe funzionare con qualsiasi tipo, ma creerai anche versioni specializzate per i tipi che richiedono una gestione personalizzata.

    Il template primario Formatter dovrebbe avere:

    • Un metodo format() che accetta un valore di tipo T e stampa: Value: <value>

    Crea una specializzazione completa per bool che stampi testo leggibile invece di 1 o 0:

    • Il metodo format() dovrebbe stampare: Boolean: true oppure Boolean: false

    Crea una specializzazione completa per const char* che aggiunga virgolette attorno alle stringhe:

    • Il metodo format() dovrebbe stampare: String: "<value>"

    Crea anche un template di funzione chiamato formatPair che accetti due valori dello stesso tipo e li stampi insieme nel formato: Pair: [<first>, <second>]

    Crea una specializzazione di formatPair per const char* che racchiuda ogni stringa tra virgolette: Pair: ["<first>", "<second>"]

  • main.cpp: leggi quattro input (ciascuno su una riga separata):
    1. Un intero
    2. Un double
    3. Un booleano come stringa (true o false)
    4. Un valore stringa

    Mostra come funzionano i tuoi formattatori creando gli oggetti Formatter appropriati e chiamando format() per ciascun tipo:

    1. Formatta l’intero usando Formatter<int>
    2. Formatta il double usando Formatter<double>
    3. Formatta il booleano usando Formatter<bool> (prima converti l’input stringa in un bool)
    4. Formatta la stringa usando Formatter<const char*>

    Mostra poi la specializzazione del template di funzione:

    1. Chiama formatPair con due interi: 10 e 20
    2. Chiama formatPair con due stringhe C: "hello" e "world"

Per esempio, con gli input 42, 3.14, true e Hello:

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

Nota come il template generico gestisce interi e double nello stesso modo, mentre le versioni specializzate per bool e const char* forniscono una formattazione personalizzata. Il compilatore seleziona automaticamente la corrispondenza più specifica per ciascun tipo utilizzato.

Provalo tu

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

using namespace std;

int main() {
    // Lee las entradas
    int intVal;
    double doubleVal;
    string boolStr;
    string strVal;
    
    cin >> intVal;
    cin >> doubleVal;
    cin >> boolStr;
    cin >> strVal;
    
    // Convierte la cadena a bool
    bool boolVal = (boolStr == "true");
    
    // TODO: Crea Formatter<int> y da formato al entero
    
    // TODO: Crea Formatter<double> y da formato al valor double
    
    // TODO: Crea Formatter<bool> y da formato al booleano
    
    // TODO: Crea Formatter<const char*> y da formato a la cadena
    // Pista: Usa strVal.c_str() para obtener const char*
    
    // TODO: Llama a formatPair con dos enteros: 10 y 20
    
    // TODO: Llama a formatPair con dos cadenas C: "hello" y "world"
    
    return 0;
}
quiz iconMettiti alla prova

Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.

Tutte le lezioni di Programmazione orientata agli oggetti

Esercitati da solo: Compilatore C++ online