Search code examples
c++crtpmethod-chaining

How to implement method chaining with inheritance?


My problem is that I can't chain methods from Derived class when I already used Base class methods. I tried to mix topmost answers from Returning a reference to the derived class from a base class method and CRTP and multilevel inheritance, but the problem is one of them is always returning the same object, the other is returning void. I want Base class being able to be inherited by any other class.

[The naive solution to this problem is to make a() virtual and override it in class Derived. But what if Base is inherited by 100 other classes and have 100 other methods to override? This is not scaling good.] [The other naive solution is to call methods from Derived class first, then from Base, but... just no]

So, is it possible to somehow compile the following snippet in native C++? (I am not interested in boost solutions). It would be ideal if main()'s code wouldn't change.

#include <iostream>
#include <type_traits>

template <typename T = void>
class Base
{
public:
    T& a();
 };

class Derived : public Base<Derived>
{
public:
    Derived& b() {std::cout << "b\n"; return *this;}
};


int main()
{
    Base base;
    base
        .a()
    ;
    
    Derived derived;
    derived
        .a()
        .b()
    ;
    
    return 0;
}

template <typename T>
T& Base<T>::a()
{
    std::cout << "a\n";
    if(std::is_same<T, void>::value)
    {
        return *this;
    }
    else
    {
        return static_cast<T&>(*this);
    }
}

If only i could write template <typename T = Base> class Base { ... :)


Solution

  • Not sure if it is what you want, but with C++17 and if constexpr, you might do:

    template <typename T = void>
    class Base
    {
    public:
        auto& a()
        {
            std::cout << "a\n";
            if constexpr (std::is_same_v<T, void>) {
                return *this;   
            } else {
                return static_cast<T&>(*this);
            }
        }
    };
    

    Demo

    Before, you might use specialization.