Template Specialization
intermediate25 min readLesson 114 of 204
Full and partial specializations, compiler precedence, and recursive composition through the primary template.
Sometimes one type needs a different implementation than the generic recipe. Specialization provides it — opt in per type, keep the generic elsewhere.
template <typename T>
struct Serializer {
static std::string to(const T& v) { return std::to_string(v); }
};
// full specialization for std::string
template <>
struct Serializer<std::string> {
static std::string to(const std::string& v) { return v; }
};
// partial specialization for every std::vector<T>
template <typename T>
struct Serializer<std::vector<T>> {
static std::string to(const std::vector<T>& v) {
std::string out = "[";
for (std::size_t i = 0; i < v.size(); ++i) {
if (i) out += ",";
out += Serializer<T>::to(v[i]); // recursion through the generic
}
return out + "]";
}
};
Reading order for the compiler: full specializations beat partial ones,
which beat the primary template. The vector case above recurses: a
std::vector<int> uses the partial, whose elements use the primary, and
a nested vector keeps recursing — generic machinery composing itself.
Use sparingly: specialization is a hook for implementations, not for changing public behavior. If the specialized type's semantics differ, a plain overload or a differently-named function is usually clearer.