Function template specialization is a process where we explicitly create a template instance/specialization for certain type of template parameter.

For example:

#include <iostream>
 
template <typename T>
void print(const T &v)
{
    std::cout << v << '\n';
}
 
int main(int argc, char const *argv[])
{
    print(1);
    print(1.0011);
    return 0;
}

Here, we might want print of argument type double to print value in scientific notation. However, as we have a generic templated function, the same code will get executed for all template types.

One way to achieve the special case, we can provide non-template print function with double parameter:

#include <iostream>
 
template <typename T>
void print(const T &v)
{
    std::cout << v << '\n';
}
 
void print(double v)
{
    std::cout << std::scientific << v << '\n';
}
 
int main(int argc, char const *argv[])
{
    print(1);
    print(1.0011);
    return 0;
}

So, when print(1.0011) is called, print(double) gets called. This works as good and is a recommended approach.

However, there is another approach of explicit template specialization where we specialize the templated function for few template types.

For example:

#include <iostream>
 
template <typename T>
void print(const T &v)
{
    std::cout << v << '\n';
}
 
template <>
void print(const double &v)
{
    std::cout << std::scientific << v << '\n';
}
 
int main(int argc, char const *argv[])
{
    print(1);
    print(1.0011);
    return 0;
}

Here, we have specified a template specialization for template type double. When print(1.0011) is invoked, this specialization is used.

Please make sure that the generic template should come first and then the specialization.

Full and half specialization

In the example above, we have a full specialization because there are no template parameters within in angular braces <>. There is another specialization where we are explicit about some template parameter and we keep other types are template. For example:

template <typename T, typename D>
void print(const T&a, const D&b)
{
}
 
template <typename D>
void print(const int&a, const D&b)
{
 
}

Here, we have created a half template specialization where we have explicitly specified int type and kept the other as template type.

Full specializations are not implicitly inline, so we need to make them inline if used them in header file which in turn included into multiple cpp files. This would break ODR and would give error.

References

  1. https://www.learncpp.com/cpp-tutorial/function-template-specialization/