Similar to function template specialization, we can also do class template specialization. For example:

#include <iostream>
 
template <typename T>
class Store
{
    T m_value{};
 
public:
    Store(T value)
        : m_value{value}
    {
    }
 
    void print() const
    {
        std::cout << m_value << '\n';
    }
};
 
int main(int argc, char const *argv[])
{
    Store<int> intValue{19};
    intValue.print();
 
    Store<double> doubleValue{19.011};
    doubleValue.print();
 
    return 0;
}

We have taken the similar example of function template specialization. Here, Store class stores a value of template type and has a member function to print it. Now, if we want to print double in scientific notation, we need to define a class template specialization.

We can do this as shown below:

#include <iostream>
 
template <typename T>
class Store
{
    T m_value{};
 
public:
    Store(T value)
        : m_value{value}
    {
    }
 
    void print() const
    {
        std::cout << m_value << '\n';
    }
};
 
template <>
class Store<double>
{
    double m_value{};
 
public:
    Store(double value)
        : m_value{value}
    {
    }
 
    void print() const
    {
        std::cout << std::scientific << m_value << '\n';
    }
};
 
int main(int argc, char const *argv[])
{
    Store<int> intValue{19};
    intValue.print();
 
    Store<double> doubleValue{19.011};
    doubleValue.print();
 
    return 0;
}

This way, Store<double> uses the specification for explicit template type double and doubleValue.print() invokes the print which prints double in scientific notation.

This is the simplest example of class template specialization. Specialized classes are treated as independent classes where we can add more functions, change the way class behave etc. Similar to function template specialization, class specialization should also be defined after the actual class template.

Specializing member functions

In the example above, just to customize the way double are printed, we have specialized the class for double whose code is totally duplicated from the original template. This is a clear example of code redundancy.

In this case, we just need to specialize the print member function for double data type. C++ allows us just to specialize the member function instead of the whole class.

We can do that as follows:

#include <iostream>
 
template <typename T>
class Store
{
    T m_value{};
 
public:
    Store(T value)
        : m_value{value}
    {
    }
 
    void print() const
    {
        std::cout << m_value << '\n';
    }
};
 
template <>
void Store<double>::print() const
{
    std::cout << std::scientific << m_value << '\n';
}
 
int main(int argc, char const *argv[])
{
    Store<int> intValue{19};
    intValue.print();
 
    Store<double> doubleValue{19.011};
    doubleValue.print();
 
    return 0;
}

Here we have specified a member function specialization for double type. By default, this function specialization is not inline and including it using header file into multiple cpp files would violet ODR.

References

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