When you implement something like:
/* 1 */ template <typename T> class MyClass { ... }; //template class for every T /* 2 */ template <> class MyClass<char> { ... }; //template class full specialization for T=char
You are saying the C++ compiler: “Please, use the first template for all the MyClass<T> instances with any T except for the MyClass<T> instances where T = char”.
The problem I see with this approach is that you must provide full implementations for the template and for the <char> specialization (full implementation means: constructors, destructor, methods and attribute declarations).
In the practice, you will meet a lot of problems where you need to do a specialization of a few methods, so, the obvious solution is: inheritance.
Look at the following code snippets:
I have an “abstract” template class called ABase<T>:
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 you can see, this class does not provide a GetA() method. I want to provide two implementations for GetA(): The default implementation, and an implementation for the <char> specialization; thus, I implement: A<T> and A<char>:
template <typename T> class A : public ABase<T> { public: A() : ABase<T>() { printf("A<T> constructor called\n"); } virtual ~A() { 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"); } virtual ~A() { printf("A<char> destructor called\n"); } inline const char& GetA() const { printf("A<char>::GetA() called\n"); return ABase::mA; } };
in my quite unuseful example, you can see that two different implementations will be called when creating instances of A<T>:
A<int> objInt; A<char> objChar;
objInt.GetA(); will call A<T>::GetA() implementation and
objChar.GetA(); will call A<char>::GetA() specialization.
I can see this like “static polymorphism” or something like “compile time polymorphism”.
The idea of inherit and provide several different methods can be useful for some kind of stuff like:
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 my example, the more fascinating thing about this is when you inherit from A:
template <typename T> class B : public A<T> { ... };
when you create an instance of B<T>: B<int> bInt; bInt.GetA(); will call the A<T>::GetA(); method; but if you instance B<char> bChar; bChar.GetA(); will call the A<char>::GetA(); specialization.
Quite powerful!!!
Thank you for a great post.
I quite like the helpful information you supply in your posts.
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.
Could you please elaborate on your question? I do not get it (sorry my non-native English).