C++ FAQ Celebrating Twenty-One Years of the C++ FAQ!!!
(Click here for a personal note from Marshall Cline.)
Section 35:
35.1 What's the idea behind templates?
35.2 What's the syntax / semantics for a "class template"?
35.3 What's the syntax / semantics for a "function template"?
35.4 How do I explicitly select which version of a function template should get called?
35.5 What is a "parameterized type"?
35.6 What is "genericity"?
35.7 My template function does something special when the template type T is int or std::string; how do I write my template so it uses the special code when T is one of those specific types?
35.8 Huh? Can you provide an example of template specialization that doesn't use foo and bar?
35.9 But most of the code in my template function is the same; is there some way to get the benefits of template specialization without duplicating all that source code?
35.10 All those templates and template specializations must slow down my program, right?
35.11 So templates are overloading, right?
35.12 Why can't I separate the definition of my templates class from its declaration and put it inside a .cpp file?
35.13 How can I avoid linker errors with my template functions? Updated!
35.14 How does the C++ keyword export help with template linker errors? Updated!
35.15 How can I avoid linker errors with my template classes? Updated!
35.16 Why do I get linker errors when I use template friends?
35.17 How can any human hope to understand these overly verbose template-based error messages?
35.18 Why am I getting errors when my template-derived-class uses a nested type it inherits from its template-base-class?
35.19 Why am I getting errors when my template-derived-class uses a member it inherits from its template-base-class?
35.20 Can the previous problem hurt me silently? Is it possible that the compiler will silently generate the wrong code?
35.21 How can I create a container-template that allows my users to supply the type of the underlying container that actually stores the values?
35.22 Follow-up to previous: can I pass in the underlying structure and the element-type separately?
35.23 Related: all those proxies must negatively reflect on the speed of my program. Don't they?
[35.8] Huh? Can you provide an example of template specialization that doesn't use foo and bar?

Yes.

One of several ways I personally use template specialization is for stringification. I usually use a template to stringify various objects of various types, but I often need to specialize the code for stringifying certain specific types. For instance, when stringifying bools I prefer "true" and "false" over "1" and "0" so I use std::boolalpha when T is bool. Also I often prefer floating point output to contain all the digits (so I can see very small differences, etc.) so I use std::setprecision when T is a floating point type. The end result usually looks something like this:

#include <iostream>
#include <sstream>
#include <iomanip>
#include <string>
#include <limits>

template<typename T> inline std::string stringify(T const& x)
{
  std::ostringstream out;
  out << x;
  return out.str();
}

template<> inline std::string stringify<bool>(bool const& x)
{
  std::ostringstream out;
  out << std::boolalpha << x;
  return out.str();
}

template<> inline std::string stringify<double>(double const& x)
{
  const int sigdigits = std::numeric_limits<double>::digits10;
  // or perhaps std::numeric_limits<double>::max_digits10 if that is available on your compiler
  std::ostringstream out;
  out << std::setprecision(sigdigits) << x;
  return out.str();
}

template<> inline std::string stringify<float>(float const& x)
{
  const int sigdigits = std::numeric_limits<float>::digits10;
  // or perhaps std::numeric_limits<float>::max_digits10 if that is available on your compiler
  std::ostringstream out;
  out << std::setprecision(sigdigits) << x;
  return out.str();
}

template<> inline std::string stringify<long double>(const long double& x)
{
  const int sigdigits = std::numeric_limits<long double>::digits10;
  // or perhaps std::numeric_limits<long_double>::max_digits10 if that is available on your compiler
  std::ostringstream out;
  out << std::setprecision(sigdigits) << x;
  return out.str();
}
Conceptually they all do the same thing: stringify the parameter. That means the observable behavior is consistent, therefore the specializations do not confuse callers. However the details for implementing that observable behavior is slightly different for bool and floating point types, so template specialization is a good approach.