C++: Inheritance on template specialization

This code:

/* 1 */ template <typename T> class MyClass { ... }; //template class for every T
 
/* 2 */ template <> class MyClass<char> { ... };  //template class full specialization for T=char

tells the C++ compiler: “The first template should be used for all instances of MyClass<T> with any T, except for the instances where T is char.”

The problem seen with this approach is that full implementations must be provided for both the template and the specialization for char (full implementation means: constructors, destructor, methods, and attribute declarations).

In practice, many situations will be encountered where only a few methods need to be specialized. The obvious solution is inheritance.

The following code snippets can be examined:

An “abstract” template class called ABase<T> is implemented:

template <typename T> class ABase
{
    protected:
        ABase()
        {
            printf("ABase<T> Constructor called\n");
        }
 
    public:
        virtual ~ABase()
        {
            printf("ABase<T> Destructor called\n");
        }
 
        void setA(const T& aA)
        {
            mA = aA;
        }
 
    protected:
        T mA;
};

As can be seen, this class does not provide a getA() method. Two implementations for getA() are intended: a default implementation and a specialized implementation for char. Therefore, A<T> and A<char> are implemented:

template <typename T> class A : public ABase<T>
{
    public:
        A() : ABase<T>()
        {
            printf("A<T> constructor called\n");
        }
 
       ~A() override
        {
            printf("A<T> destructor called\n");
        }
 
        inline const T& getA() const
        {
            printf("A<T>::getA() called\n");
            return ABase::mA;
        }
};
 
// A specialization for T = char
template <> class A<char> : public ABase<char>
{
    public:
    A() : ABase<char>()
    {
        printf("A<char> constructor called\n");
    }
 
   ~A() override
    {
        printf("A<char> destructor called\n");
    }
 
    inline const char& getA() const
    {
        printf("A<char>::getA() called\n");
        return ABase::mA;
    }
};

In this somewhat unhelpful example, it can be seen that two different implementations will be called when instances of A<T> are created:

objInt.getA(); will call the A<T>::getA() implementation, and
objChar.getA(); will call the A<char>::getA() specialization.

A<int> objInt;
A<char> objChar;

This is seen as “static polymorphism” or something like “compile-time polymorphism.”

The idea of using inheritance to provide several different methods can be useful for certain scenarios, such as:

template <typename T> class StringBase { ... };

and

template <> class String<char> : public StringBase<char> { ... }; //providing a method const char* c_str() const;
 
template <> class String<wchar_t> : public StringBase<wchar_t> { ... }; //providing something like const wchar_t* w_str() const;

Continuing with this example, the most fascinating thing about this is when inheritance from A is used:

template <typename T>
class B : public A<T>
{
  ...
};

When an instance of B<T> is created, for example, B<int> bInt;, bInt.getA(); will call the A<T>::getA(); method. However, if an instance of B<char> is created, for example, B<char> bChar;, bChar.getA(); will call the A<char>::getA(); specialization.

Quite powerful!

4 thoughts on “C++: Inheritance on template specialization

  1. inline const char& GetA() const
    {
    printf(“A::GetA() called\n”);
    return ABase::mA;
    }

    How do you place that in a source file? I’ve search alot and can’t figure out how. I reckon now that it is specialize, it is now possible to place it in a soruce file without shinanigans.

Leave a reply to toasty redhead Cancel reply