When do we use template specializations for in C++, if not for SFINAE or metaprogramming? type_traits
, enable_if
and others rely on it a lot, but I'm more curious about situations which are more "obvious" uses of templates - type-agnostic algorithms and objects.
One can easily create an artificial example of algorithm which does completely different things for different types, so I'd like to limit the scope to more "real-life" scenarios. Specifically, the following properties should be satisfied:
- One can formulate an invariant of a generic version of template (so it makes sense to talk about specialization), and
- Specialized version do not violate any invariants of the generic version (if it does, it's probably a bad specialization and a separate class/function should be created instead).
I have three examples in my mind:
std::vector<bool>
. It's known to have different interface from genericvector
(1, 2) and therefore I consider it a bad example - it does not satisfy property 2.std::hash
. Despite it does not have "generic" implementation, it has "generic" invariant.std::swap
. It satisfies both properties.
These examples, though, look very specific to me. I'm wondering if it's possible to describe when one should use template specialization. E.g. "if you have a type-agnostic container which has a strictly better implementation for some specific type" is probably true, but, again, rather specific.
vector<bool>
sucks, am I right?” (which, though true, is unrelated to specializations). The remaining question could be improved (or even answered) by doing a bit more research. Perhaps you'd like to learn more about templates, the difference between class- and function-templates, interactions between function template specializations and function overloading, and most importantly: using (partial) specializations for SFINAE. E.g. the C++11type_traits
header uses a lot of template specializations.template<class T> T getArgument(LanguageInterpreter *i, int argumentIndex) = delete;
and then specialize it for the particular argument types you need. (E.g.template<> string getArgument(LanguageInterpreter *i, int index) {return i->getArgString(index);}
)