cpp core · advanced
Templates: Full Specialization, Partial Specialization, Explicit Instantiation
Template specialization: primary template = fallback; specializations = overrides. Full specialization (template<>): fixes ALL template parameters; works for both classes and functions. Partial specialization: fixes SOME parameters; class templates ONLY (not function templates). Compiler selects most specific match: full > partial > primary. Function template specialization pitfall: specs not in overload resolution; overloads preferred — prefer regular function overloads over function template specializations (Herb Sutter rule). Type traits via specialization: primary=false_type, T* specialization=true_type — basis of <type_traits>. Explicit instantiation: template class Foo<double>; in one .cpp = generate once. extern template class Foo<double>; in header = suppress elsewhere. When to use: specialization for different struct layout; if constexpr for different body; concepts for overload selection.
Full specialization: template<> struct Foo<int> {} — fixes all params; partial specialization: template<typename T> struct Foo<T*> {} — fixes some (class templates only); prefer overloading over function template specialization; explicit instantiation for build-time reduction.
The code
// Template Specialization — full and partial
// Primary template:template <typename T>struct Storage { void store(T val) { /* generic */ } T load() { /* generic */ }};
// FULL specialization — fix ALL template params:template <>struct Storage<bool> { // specific to bool only void store(bool val) { data_ = val ? 1 : 0; /* pack into byte */ } bool load() { return data_ != 0; }
private: uint8_t data_{};};
// PARTIAL specialization — fix SOME params (only for class templates):template <typename T>struct Storage<T*> { // specialization for any pointer type void store(T* p) { ptr_ = p; } T* load() { return ptr_; }
private: T* ptr_{};};
// Usage — compiler picks most specific match:Storage<int> s1; // primary templateStorage<bool> s2; // full specializationStorage<int*> s3; // partial specialization (T=int, T*=int*)
// FUNCTION template specialization:template <typename T>T max(T a, T b) { return a > b ? a : b;}
template <>const char* max<const char*>(const char* a, const char* b) { return strcmp(a, b) > 0 ? a : b; // string compare, not pointer compare}
// Prefer overloading over function specialization!// Function specializations don't participate in overload resolution// → unintuitive: overload of primary is preferred over specialization
// Explicit instantiation — force generation without calling:template class Storage<double>; // generates Storage<double> in this TU// Prevents implicit instantiation in other TUs → faster build
// extern template — suppress implicit instantiation in THIS TU:extern template class Storage<int>; // definition elsewhereWhat this lesson walks through
- 01Primary template and full specialization
- 02Partial specialization — only for class templates
- 03Function template specialization — prefer overloading
- 04Explicit instantiation — controlling template code generation
- 05Specialization for type traits — implementing is_pointer
- 06Template specialization vs if constexpr — when to use each
A primary template provides the generic behavior. A full specialization (template<>) overrides it for ONE specific set of template arguments. The compiler uses the most specific match. Full specialization: all template parameters are fixed. Useful when a type requires completely different behavior — e.g. Storage<bool> packs bits instead of storing a full bool.
See it animated — step by step, at your own pace
Unlock the full interactive walkthrough of Templates: Full Specialization, Partial Specialization, Explicit Instantiation and 100+ animated C++ interview lessons.