c++crtpdiamond-problemstatic-polymorphism

How to handle multiple inheritance of same methods or diamond problem with CRTP static polymorphism?


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.


Solution

  • 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