Full vs Partial Template Specialization in C++
In C++, template specialization allows developers to customize generic code for specific data types or conditions. This article provides a clear comparison between full (explicit) template specialization and partial template specialization, detailing their syntax, behavioral rules, and key differences—including how they apply to class and function templates.
Understanding Full Template Specialization
Full template specialization—also referred to as explicit specialization—occurs when every generic template parameter is replaced with a concrete, specific type. Once fully specialized, no generic type parameters remain for the compiler to deduce.
Key Characteristics:
- Starts with an empty template parameter list:
template <>. - Replaces all template parameters with specific types.
- Can be applied to class templates, struct templates, variable templates, and function templates.
Example:
// Primary template
template <typename T>
class Storage {
public:
void print() { /* Generic implementation */ }
};
// Full specialization for type 'bool'
template <>
class Storage<bool> {
public:
void print() { /* Optimized implementation for bool */ }
};Full specialization can also be applied to functions:
template <typename T>
void process(T value) { /* Generic implementation */ }
template <>
void process<int>(int value) { /* Specialized implementation for int */ }Understanding Partial Template Specialization
Partial template specialization occurs when only a subset of template parameters are specified, or when the template parameters are constrained to a particular pattern (such as pointers, references, or arrays). In this scenario, generic types still remain in the template header.
Key Characteristics:
- The template header retains one or more parameters:
template <typename T>. - Customizes behavior for a family of types rather than a single
concrete type (e.g., all pointer types
T*). - Allowed for class templates, struct templates, and variable templates (since C++14).
- Not allowed for function templates in standard C++.
Example:
// Primary template with two parameters
template <typename T1, typename T2>
class KeyValuePair {
public:
void display();
};
// Partial specialization: T2 is fixed to 'int', T1 remains generic
template <typename T1>
class KeyValuePair<T1, int> {
public:
void display();
};
// Partial specialization for pointer types
template <typename T1, typename T2>
class KeyValuePair<T1*, T2*> {
public:
void display();
};The Function Template Limitation
A common source of confusion in C++ is that function templates cannot be partially specialized.
// Primary function template
template <typename T1, typename T2>
void display(T1 a, T2 b);
// COMPILE ERROR: Partial specialization of a function is not allowed
template <typename T1>
void display<T1, int>(T1 a, int b); To achieve the equivalent of partial specialization for functions, you must use function overloading:
// Function overload achieving the desired behavior
template <typename T1>
void display(T1 a, int b);Alternatively, you can delegate the function logic to a static member of a partially specialized class or struct.
Summary of Differences
| Feature | Full Specialization | Partial Specialization |
|---|---|---|
| Syntax | template <> |
template <typename T, ...> |
| Parameters Resolved | All parameters are specified | Some parameters are specified or constrained |
| Applicable to Classes | Yes | Yes |
| Applicable to Functions | Yes | No (use overloading instead) |
| Scope of Target | A single, exact type | A subset or structural pattern of types
(e.g., T*) |