Skip to content

🎯 Template Specialization — Handle Edge Cases

Specialization cho phép customize behavior cho specific types — xử lý edge cases mà generic template không cover.

Tại sao cần Specialization?

cpp
template<typename T>
T maximum(T a, T b) {
    return (a > b) ? a : b;
}

int main() {
    std::cout << maximum(10, 20) << std::endl;  // ✅ 20
    std::cout << maximum(3.14, 2.71) << std::endl;  // ✅ 3.14
    
    // ❌ C-strings compare POINTERS, not content!
    const char* s1 = "apple";
    const char* s2 = "banana";
    std::cout << maximum(s1, s2) << std::endl;  // Compares addresses!
    
    return 0;
}

Giải pháp: Specialize cho const char*


Full Specialization (Function)

cpp
#include <iostream>
#include <cstring>

// Primary template
template<typename T>
T maximum(T a, T b) {
    return (a > b) ? a : b;
}

// Full specialization for const char*
template<>
const char* maximum<const char*>(const char* a, const char* b) {
    return (std::strcmp(a, b) > 0) ? a : b;
}

int main() {
    std::cout << maximum(10, 20) << std::endl;  // 20
    
    const char* s1 = "apple";
    const char* s2 = "banana";
    std::cout << maximum(s1, s2) << std::endl;  // banana ✅
    
    return 0;
}

Full Specialization (Class)

cpp
#include <iostream>
#include <cstring>

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

// Full specialization for bool
template<>
class Printer<bool> {
public:
    static void print(bool value) {
        std::cout << "Bool: " << (value ? "true" : "false") << std::endl;
    }
};

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

int main() {
    Printer<int>::print(42);           // Generic: 42
    Printer<double>::print(3.14);      // Generic: 3.14
    Printer<bool>::print(true);        // Bool: true
    Printer<const char*>::print("hi"); // C-String: "hi"
    
    return 0;
}

Partial Specialization

Partial specialization chỉ áp dụng cho class templates (không cho function templates).

Example: Pointer Specialization

cpp
#include <iostream>

// Primary template
template<typename T>
class TypeInfo {
public:
    static void describe() {
        std::cout << "Regular type" << std::endl;
    }
};

// Partial specialization for pointers
template<typename T>
class TypeInfo<T*> {
public:
    static void describe() {
        std::cout << "Pointer to ";
        TypeInfo<T>::describe();
    }
};

// Partial specialization for references
template<typename T>
class TypeInfo<T&> {
public:
    static void describe() {
        std::cout << "Reference to ";
        TypeInfo<T>::describe();
    }
};

int main() {
    TypeInfo<int>::describe();      // Regular type
    TypeInfo<int*>::describe();     // Pointer to Regular type
    TypeInfo<int**>::describe();    // Pointer to Pointer to Regular type
    TypeInfo<int&>::describe();     // Reference to Regular type
    
    return 0;
}

Example: Array Specialization

cpp
template<typename T>
class Container {
    T data_;
public:
    Container(const T& d) : data_(d) {}
    void print() { std::cout << "Single: " << data_ << std::endl; }
};

// Partial specialization for arrays
template<typename T, std::size_t N>
class Container<T[N]> {
    T data_[N];
public:
    Container(const T (&arr)[N]) {
        std::copy(std::begin(arr), std::end(arr), data_);
    }
    void print() {
        std::cout << "Array of " << N << ": ";
        for (const auto& elem : data_) {
            std::cout << elem << " ";
        }
        std::cout << std::endl;
    }
};

int main() {
    Container<int> single(42);
    single.print();  // Single: 42
    
    int arr[] = {1, 2, 3, 4, 5};
    Container<int[5]> array(arr);
    array.print();  // Array of 5: 1 2 3 4 5
    
    return 0;
}

Partial Specialization Patterns

One of Multiple Parameters

cpp
template<typename T, typename U>
class Pair {
public:
    static void describe() {
        std::cout << "Generic Pair" << std::endl;
    }
};

// Specialize when both types are the same
template<typename T>
class Pair<T, T> {
public:
    static void describe() {
        std::cout << "Same-type Pair" << std::endl;
    }
};

// Specialize when second is int
template<typename T>
class Pair<T, int> {
public:
    static void describe() {
        std::cout << "Pair with int second" << std::endl;
    }
};

int main() {
    Pair<double, std::string>::describe();  // Generic Pair
    Pair<int, int>::describe();             // Same-type Pair
    Pair<std::string, int>::describe();     // Pair with int second
    
    return 0;
}

Type Traits Implementation

cpp
#include <iostream>

// Primary: not a pointer
template<typename T>
struct is_pointer {
    static constexpr bool value = false;
};

// Partial specialization: IS a pointer
template<typename T>
struct is_pointer<T*> {
    static constexpr bool value = true;
};

// Helper variable template (C++14)
template<typename T>
constexpr bool is_pointer_v = is_pointer<T>::value;

int main() {
    std::cout << std::boolalpha;
    std::cout << is_pointer_v<int> << std::endl;    // false
    std::cout << is_pointer_v<int*> << std::endl;   // true
    std::cout << is_pointer_v<int**> << std::endl;  // true
    
    return 0;
}

More Type Traits

cpp
// Remove const
template<typename T>
struct remove_const {
    using type = T;
};

template<typename T>
struct remove_const<const T> {
    using type = T;
};

template<typename T>
using remove_const_t = typename remove_const<T>::type;

// Remove reference
template<typename T>
struct remove_reference {
    using type = T;
};

template<typename T>
struct remove_reference<T&> {
    using type = T;
};

template<typename T>
struct remove_reference<T&&> {
    using type = T;
};

template<typename T>
using remove_reference_t = typename remove_reference<T>::type;

Priority Order

Compiler chọn theo thứ tự ưu tiên:

┌─────────────────────────────────────────────────────────────────┐
│                 SPECIALIZATION PRIORITY                         │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  1. Non-template function (exact match)                         │
│  2. Full specialization                                         │
│  3. Partial specialization (more specific wins)                │
│  4. Primary template                                            │
│                                                                 │
│  Example:                                                       │
│  Template\<T, U\>           ← Primary                            │
│  Template\<T, T\>           ← Partial (same types)               │
│  Template\<T, int\>         ← Partial (int second)               │
│  Template\<int, int\>       ← Full specialization                │
│                                                                 │
│  Template\<int, int\> wins over Template\<T, T\>!                  │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

Real-world Example: std::vector<bool>

cpp
// This is why std::vector<bool> is "special" (and controversial)

// Primary template (simplified)
template<typename T>
class vector {
    T* data_;
    // Normal storage
};

// Specialization for bool — packed bits
template<>
class vector<bool> {
    unsigned char* data_;
    // 8 bools per byte — space efficient but different behavior!
};

// ⚠️ Đây là lý do vector<bool> controversial:
// - operator[] không trả về bool&, mà proxy object
// - Không thể lấy pointer tới element

📚 Tổng kết

TypeSyntaxUse Case
Full (function)template<> T func<Type>(...)Specific type handling
Full (class)template<> class Foo<Type>Complete rewrite
Partialtemplate<typename T> class Foo<T*>Pattern matching
Type traitsRemove const/ref/pointerMetaprogramming

⚠️ Avoid Over-specialization

Quá nhiều specializations làm code khó maintain. Ưu tiên dùng concepts (C++20) thay vì SFINAE + specialization.


➡️ Tiếp theo

Tiếp theo: C++20 Concepts — Modern template constraints.