As jalf suggests in the comments, you probably want to use a variant of the Curiously Recurring Template Pattern (CRTP). That is, make MyHashingSolution
a class template parametrised by the derived class:
template <typename D>
struct MyHashingSolution {
typedef D Derived;
void UpdateHash(int idx, int val) {
...
}
void RecalcHash() {
...
UpdateHash(idx, derived().GetState(idx));
...
}
private:
// Just for convenience
Derived& derived() { return *static_cast<Derived*>(this); }
};
In this case, because you want the derived State
class to also be a template, you need to take the slightly unusual step of declaring State
as a class template that takes a template template parameter:
template <template <class T> class HashingSolution>
struct State : public HashingSolution<State<HashingSolution> > {
typedef HashingSolution<State<HashingSolution> > Parent;
void Update(int idx, int val) {
Parent::UpdateHash(idx, val); // g++ requires "Parent::"
}
int GetState(int idx) {
return ...;
}
};
The key point is that, provided State
inherits from HashingSolution<State<HashingSolution> >
, Derived
is a derived class of HashingSolution<State<HashingSolution> >
so the static_cast<Derived*>(this)
downcast in HashingSolution<State>::derived()
compiles and works correctly. (If you mess up and derive State
from HashingSolution<SomeOtherType>
instead and then try something that involves a call to derived()
, the compiler will complain as the requirements for static_cast<>
are not met.)
Then declare the concrete State
class you want to use like so:
typedef State<MyHashingSolution> MyState;
Unfortunately this solution has the side effect that you will need to change DummyHashingSolution
(and any other such types) to templates that ignore their one template argument, in order to make them usable as template template arguments.