Menu
Coddy logo textTech

Template Specialization

Part of the Object Oriented Programming section of Coddy's C++ journey — lesson 66 of 104.

Sometimes a generic template doesn't work well for every type. For example, comparing C-style strings with > compares pointer addresses, not the actual text. Template specialization lets you provide a custom implementation for specific types while keeping the generic version for everything else.

A full specialization replaces the entire template for one specific type. You declare it with an empty template parameter list and specify the concrete type:

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

// Full specialization for 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

Function templates can also be specialized:

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);              // Uses generic version
isEqual("hi", "hi");        // Uses specialized version

The compiler always prefers the most specific match - if a specialization exists for the exact type being used, it will be chosen over the generic template.

challenge icon

Challenge

Easy

Let's build a type-aware formatter system that demonstrates how template specialization lets you customize behavior for specific types while maintaining a generic fallback for everything else.

You'll create two files to organize your template code:

  • Formatter.h: Define a class template called Formatter that formats values for display. Your generic template should work with any type, but you'll also create specialized versions for types that need custom handling.

    The primary Formatter template should have:

    • A format() method that takes a value of type T and prints: Value: <value>

    Create a full specialization for bool that prints human-readable text instead of 1 or 0:

    • The format() method should print: Boolean: true or Boolean: false

    Create a full specialization for const char* that adds quotes around strings:

    • The format() method should print: String: "<value>"

    Also create a function template called formatPair that takes two values of the same type and prints them together as: Pair: [<first>, <second>]

    Create a specialization of formatPair for const char* that wraps each string in quotes: Pair: ["<first>", "<second>"]

  • main.cpp: Read four inputs (each on a separate line):
    1. An integer
    2. A double
    3. A boolean as string (true or false)
    4. A string value

    Demonstrate your formatters by creating appropriate Formatter objects and calling format() for each type:

    1. Format the integer using Formatter<int>
    2. Format the double using Formatter<double>
    3. Format the boolean using Formatter<bool> (convert the string input to a bool first)
    4. Format the string using Formatter<const char*>

    Then demonstrate the function template specialization:

    1. Call formatPair with two integers: 10 and 20
    2. Call formatPair with two C-strings: "hello" and "world"

For example, with inputs 42, 3.14, true, and Hello:

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

Notice how the generic template handles integers and doubles identically, while the specialized versions for bool and const char* provide custom formatting. The compiler automatically selects the most specific match for each type you use.

Cheat sheet

Template specialization allows you to provide custom implementations for specific types while keeping a generic version for all other types.

Full Specialization Syntax

Declare a specialization with an empty template parameter list template <> and specify the concrete type:

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

// Full specialization for const char*
template <>
class Printer<const char*> {
public:
    void print(const char* value) {
        std::cout << "String: " << value << std::endl;
    }
};

Function Template Specialization

Function templates can also be specialized:

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;
}

Compiler Selection

The compiler always prefers the most specific match - if a specialization exists for the exact type being used, it will be chosen over the generic template.

Try it yourself

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

using namespace std;

int main() {
    // Read inputs
    int intVal;
    double doubleVal;
    string boolStr;
    string strVal;
    
    cin >> intVal;
    cin >> doubleVal;
    cin >> boolStr;
    cin >> strVal;
    
    // Convert string to bool
    bool boolVal = (boolStr == "true");
    
    // TODO: Create Formatter<int> and format the integer
    
    // TODO: Create Formatter<double> and format the double
    
    // TODO: Create Formatter<bool> and format the boolean
    
    // TODO: Create Formatter<const char*> and format the string
    // Hint: Use strVal.c_str() to get const char*
    
    // TODO: Call formatPair with two integers: 10 and 20
    
    // TODO: Call formatPair with two C-strings: "hello" and "world"
    
    return 0;
}
quiz iconTest yourself

This lesson includes a short quiz. Start the lesson to answer it and track your progress.

All lessons in Object Oriented Programming