fhw72
fhw72

Reputation: 1154

Usage of CRTP in a call chain

In my widget library I'd like to implement some kind of call chain to initialize a user supplied VIEW class which might(!) be derived from another class which adds some additional functionality like this:

#include <iostream>

template<typename VIEW>
struct App
{
    VIEW view;
    void init() {view.initialize(); }
};

template<typename DERIVED>
struct SpecializedView
{
    void initialize()
    {
        std::cout << "SpecializedView" << std::endl;
        static_cast<DERIVED*>(this)->initialize();
    }
};

struct UserView : SpecializedView<UserView>
{
    void initialize() {std::cout << "UserView" << std::endl; }
};

int _tmain(int argc, _TCHAR* argv[])
{
    // Cannot be altered to: App<SpecializedView<UserView> > app;
    App<UserView> app; 
    app.init();
    return 0;
}

Is it possible to achieve some kind of call chain (if the user supplied VIEW class is derived from "SpecializedView") such that the output will be:

console output:

SpecializedView
UserView

Of course it would be easy to instantiate variable app with the type derived from but this code is hidden in the library and should not be alterable. In other words: The library code should only get the user derived type as parameter.

Upvotes: 2

Views: 274

Answers (1)

krlmlr
krlmlr

Reputation: 25464

You could write another function that calls initialize() on the class and on the base class if it exists and defines an initialize() method, too:

template <class T>
void callInitialize(T* t) {
    t->initialize();
    IF_EXISTS(base_class<T>::bc::initialize)
        callInitialize<base_class<T>::bc>(t);
}

Of course, the order of the calls can be reversed.

See Is it possible to write a template to check for a function's existence? on the implementation of IF_EXISTS. Also, base_class<T> is not a standard construct, and this answer suggests that this cannot be done automatically. The semantics would look like this:

template<T>
struct base_class<T> {
    typedef void bc;
};

template<>
struct base_class<UserView> {
    typedef SpecializedView<UserView> bc;
};

Perhaps your framework permits a semi-automatic way to do this.

Upvotes: 1

Related Questions