I want to implement polymorphism statically with CRTP. I want to create several base classes that provide functionalities. However the functionalities can be overlapping. However if they overlap, they are identical.
Suppose I have
template<class derived> class Boxer {
public:
void walk(int nsteps) {
for (auto _ = nsteps; _--;) static_cast<derived&>(*this).step();
}
void punch() { static_cast<derived&>(*this).moveArm(); }
protected:
~Boxer() = default;
};
template<class derived> class ChessPlayer {
public:
void walk(int nsteps) {
for (auto _ = nsteps; _--;) static_cast<derived&>(*this).step();
}
void playChess() { static_cast<derived&>(*this).think(); }
protected:
~ChessPlayer() = default;
};
class ChessBoxer : public Boxer<ChessBoxer>, public ChessPlayer<ChessBoxer> {
public:
void step() { std::cout << "one step at a time \n"; }
void moveArm() { std::cout << "moving my arm\n"; }
void think() { std::cout << "thinking\n"; }
};
int main(int argc, const char * argv[]) {
ChessBoxer vec;
vec.walk();
vec.punch();
vec.playChess();
return 0;
}
Both Boxer
and Chess Player
provide walk
. Both definition of walk
are identical.
By the way, I could (and probably I should) rewrite the code above to avoid the duplication of walk
's code .
template<class derived, class top> class Walker {
public:
void walk(int nsteps) {
for (auto _ = nsteps; _--;) static_cast<top&>(*this).step();
}
protected:
~Walker() = default;
};
template<class derived> class Boxer : public Walker<Boxer<derived>, derived> {
public:
void punch() { static_cast<derived&>(*this).moveArm(); }
protected:
~Boxer() = default;
};
template<class derived> class ChessPlayer : public Walker<ChessPlayer<derived>, derived> {
public:
void playChess() { static_cast<derived&>(*this).think(); }
protected:
~ChessPlayer() = default;
};
class ChessBoxer : public Boxer<ChessBoxer>, public ChessPlayer<ChessBoxer> {
public:
void step() { std::cout << "one step at \n"; }
void moveArm() { std::cout << "moving my arm\n"; }
void think() { std::cout << "thinking\n"; }
};
int main(int argc, const char * argv[]) {
ChessBoxer vec;
vec.walk(3);
vec.punch();
vec.playChess();
return 0;
}
But still that creates the diamond problem.
How can I solve this problem, keeping static polymorphism? Also I want the final derived class to not have to bother with technicalities.
I found the answer to my question. I do not take credit for the solution.
One possible solution can be found at the following webpage https://www.fluentcpp.com/2018/08/28/removing-duplicates-crtp-base-classes/ of Jonathan Boccara's blog.
Another solution is provided in Matthew Borkowski's comment within the same page, and it links to the code http://coliru.stacked-crooked.com/a/463db3673b139429