Can I call an unspecialized template method from a specialized one?
This is easy when using inheritance:
class SomeBaseClass {
virtual void DoWork() { /* Do something */ }
};
class SomeClass : public SomeBaseClass {
void DoWork() {
// Do something first
SomeBaseClass::DoWork();
}
};
But is a bit different when using templates:
template <class T>
class SomeClass {
void DoWork();
};
template<class T>
void SomeClass<T>::DoWork() { /* Do something */}
template<>
void SomeClass<int>::DoWork() {
// Do something first
DoWork<>(); // Call method from line 8
}
My generic DoWork function has a lot of really good code in it that I'd hate to duplicate. My specialized one just has an extra step that it needs to perform when a specific type is used.
You're thinking about this the wrong way. The solution is not to have your class specialized, but to have your function specialized. What I mean here is to use tag dispatch
That is, declare two private
helper functions in your class named DoWorkHelper
, one of which is overloaded for the specialized type, and the other not.
The way we do this is to wrap our type in a 'tag' that is basically an empty struct, and then specialize the tag for our type of interest:
namespace SomeClassDetail{
template<class T>
struct specialized_tag : std::false_type{};
template<>
struct specialized_tag<int>: std::true_type{};
}
true_type
and false_type
are essentially wrappers for boolean true
and false
. They're nice because they're types and not values (and when we template we care all about types)
Next, we'll declare our class with aforementioned overloads:
template <class T>
class SomeClass {
public:
void DoWork();
private:
void DoWorkHelper(std::true_type);
void DoWorkHelper(std::false_type);
};
The idea here is that true_type
means "Yes, this function is for the specialized version!"
Here's what the definitions look like:
template<class T>
void SomeClass<T>::DoWork()
{
DoWorkHelper(typename SomeClassDetail::specialized_tag<T>::type{});
}
template<class T>
void SomeClass<T>::DoWorkHelper(std::true_type)
{
std::cout << "Specialized DoWork\n";
DoWorkHelper(std::false_type());
}
template<class T>
void SomeClass<T>::DoWorkHelper(std::false_type)
{
std::cout << "Unspecialized DoWork\n";
}
That's it. The specialized version will do its thing, and then call the unspecialized version, and the unspecialized version (for all other T
), will simply do its thing.