1

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 { ... :)

Pako
  • 15
  • 4

1 Answers1

3

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.

Jarod42
  • 203,559
  • 14
  • 181
  • 302
  • What do you mean by "Before, you might use specialization"? – Pako Feb 25 '21 at 14:21
  • 1
    Specialize the whole class: `template class Base { T& a() { return static_cast(*this); } }; template<> class Base { Base& a() { return *this; } }` or specialize the method (return type should then be `std::conditional_t, Base, T>`) – Jarod42 Feb 25 '21 at 14:46
  • Thanks, that was very helpful. – Pako Feb 25 '21 at 14:48