2

I know there are some some pitfalls when mixing inheritance and templates, but I'd like to know if the code below (which compiles and seems to run well) is "legal" and wellformed.

struct ISession {
    virtual ~ISession() = deafult;
    virtual void run() = 0;
};

template <typename Derived>
struct SessionBase : public ISession {
    SessionBase() {
        static_assert(is_base_of_v<SessionBase<Derived>, Derived>);
    }

    void run() override {
        derived().connect();
    }
    
    Derived& derived() {
        return static_cast<Derived&>(*this);
    }
};

struct PlainSession : public SessionBase<PlainSession> {
    void connect() {
        // do connect plain
    }
};

struct SslSession : public SessionBase<SslSession> {
    void connect() {
        // do connect ssl
    }
};

int main(int argc, char *argv[])
{
    list<unique_ptr<ISession>> sessions;
    sessions.emplace_back(make_unique<PlainSession>());
    sessions.emplace_back(make_unique<SslSession>());
    for_each(sessions.begin(), sessions.end(), [](auto& session) { session->run(); });
}
Jarod42
  • 203,559
  • 14
  • 181
  • 302
Jerome
  • 25
  • 4
  • what pitfalls do you refer to? Why do you think the code could be problematic? You could replace `SessionBase` with a hypothetical `SessionBase_SslSession` and the effect would be more or less the same – 463035818_is_not_an_ai Nov 12 '21 at 14:12
  • 4
    This is an application of the [Curiously Recurring Template Pattern (CRTP)](https://stackoverflow.com/questions/4173254/what-is-the-curiously-recurring-template-pattern-crtp) and at first glance your code seems fine. I would just recommend adding a `static_assert` like `static_assert(std::is_base_of_v, Derived>);` to make sure someone doesn't try to use `SessionBase` incorrectly. Edit : I'd also consider making `SessionBase` abstract. – François Andrieux Nov 12 '21 at 14:14
  • François, thanks for the answer and advise ! – Jerome Nov 12 '21 at 19:09

1 Answers1

1

The "pitfall" is that you cannot have a member template that is also virtual. That would result in an unknown number of virtual functions, potentially growing for each new use of the class.

template<typename T>
virtual void use(T);   // not possible

As long as it is either a template or virtual, but not both, it is ok.

BoP
  • 2,310
  • 1
  • 15
  • 24