There’s an existing question/answer that describes what template subclassing means, and how it’s used in SeqAn. Let me give a simpler example here.
// No default `Spec` given = “virtual” base class!
template <typename Spec> struct Fruit {};
template <typename Spec>
inline void eat(Fruit<Spec> const&) {
std::cout << "nibbling an unknown fruit\n";
}
Note that methods in template subclassing are always free functions, since method dispatch works strictly via overloading, not overriding, as in conventional subclassing.
This defines a base class for Fruit
s, and one method, eat
, which can be called on any fruit.
We will now define a hierarchy of specialisations (“subclasses”). First, simple ones; these are simply type tags, which will be plugged into the Spec
template argument:
struct Orange;
struct Apple;
That’s it. We don’t even need to define these tags in our example, declaring them is enough (but for more complex cases definitions may become necessary; in SeqAn, type tags are always defined).
Now, here’s an override of the eat
method for Apple
s:
template <>
inline void eat(Fruit<Apple> const&) {
std::cout << "scrunching an apple\n";
}
Since we don’t override the method for Orange
s, those will always call the base class method.
Here are some more specialisations, for citrus fruits (a subclass hierarchy):
struct Lemon;
struct Lime;
template <typename Spec = Lemon> struct Citrus { };
Note that, unlike for Apple
s and Orange
s, Citrus
is itself a template that can be subclassed. We could now override eat
for Citrus
fruits the same as before, but I want to show how a subclass method can dispatch to a base class method; to do this, let’s introduce a helper function template eat_citrus
, which will be called from eat
:
template <typename Spec>
inline void eat(Fruit<Citrus<Spec>> const&) {
eat_citrus<Spec>();
}
Here’s the base class definition of eat_citrus
for any Citrus
:
template <typename Tag = Lemon>
inline void eat_citrus() {
std::cout << "ew, that’s sour!\n";
}
And here’s the override for Lime
s:
template <>
inline void eat_citrus<Lime>() {
std::cout << "nice taste, but ";
eat_citrus<>(); // Calls the base class method.
}
Finally, if we use these classes as follows:
// Does not work, since `Fruit` is “virtual”:
// Fruit<> fruit;
Fruit<Orange> orange;
Fruit<Apple> apple;
Fruit<Citrus<>> lemon;
Fruit<Citrus<Lime>> lime;
eat(orange);
eat(apple);
eat(lemon);
eat(lime);
… we get this output:
nibbling an unknown fruit
scrunching an apple
ew, that’s sour!
nice taste, but ew, that’s sour!
Runnable code on Coliru
In SeqAn, the above is done slightly differently; I’ve changed it here for simplicity and, to be honest, because it’s been years since I’ve worked with SeqAn and I don’t remember the details. If I remember correctly, eat_citrus
isn’t actually necessary and tag dispatch + overloading (as mentioned by Yuki) would be used here instead of template specialisation.
Also note that my code doesn’t use any actual inheritance in C++ parlance (i.e. Fruit<Apple>
doesn’t inherit from Fruit<whatever>
). This isn’t strictly necessary but often quite useful, and IIRC most SeqAn class templates do also actually inherit their base class.