Home > Tutorials > How to write a generic delegate class with C++ and Templates. (Tutorial)

How to write a generic delegate class with C++ and Templates. (Tutorial)

Delegate Tutorial C++

Good morning, it is a cold but beautiful Saturday right now in Amsterdam and I decided to write a new tutorial for my blog. This time not about Objective C but about the world’s sexiest things after microchips: C++, templates and function pointers to methods.
During the last week I was improving code in my game engine and while implementing a messaging system for my objects I stumbled over the problem that function pointers are actually great but don’t work fine with class methods.
C++11 has this great template std::function which I adore and that can handle class methods with std::bind as well. But in my situation it was not suitable and so I had to think of my own solution.

The problem:
The problem I had to solve was to implement an EventHandler system which can take any arbitrary function or class method. In ActionScript, the coder can call the method stage.addEventListener (MOUSE_EVENT.click, …) to add listeners to certain objects which will than receive events, like in this case mouse clicks. I adored the idea behind it and wanted to implement something like this as well.

REResponder -> Callback to Class Methods:
Our function will have to overloads. One will take a lambda function and the other one will take a class method which gets called when it receives an event. The lambda overload will take a std::function argument while the class method overload will take our own class. In this tutorial I will only write about the Responder method as the lambda method is actually pretty easy to implement.

So let’s see what we have:

typedef void* id;			// thanks to apple for that typedef

template <class T>
class RESelector: {
public:
     RESelector(T* _target, void (T::*_func)(id, RE_MSG_CODE), id _msgObj,  RE_MSG_CATEGORY _category){
         this->target = _target;
         this->category = _category;
         this->msgObj = _msgObj;
         this->actionFunc = _func;
    };

    void fire (RE_MSG_CODE code){
         (this->target->*actionFunc)(this->msgObj, code);
    };

    Inline RE_MSG_CATEGORY getCategory() const {
         return this->category;
    }

private:
    T* target;
    id msgObj;
    RE_MSG_CATEGORY category;
    void (T::*actionFunc)(id, RE_MSG_CODE);
};

typedef std::vector<id> SelectorCache;
typedef std::vector<RE_MSG_CODE> Messages;

class REMessageHandler {
    private:
	Messages *msgCache;
	SelectorCache *selectorCache;
	public:
	template<class T>
	void addEventListener(REResponder<T> *responder) {
	    selectorCache->push_back((id)responder);
        };

        Inline void postEvent(RE_MSG_CODE code){
            this->msgCache->push_back(code);
        };
	void evaluateMessages();
};

First of all, don’t worry about RE_MSG_CODE and RE_MSG_CATEGORY. It is just my way of decoding messages but doesn’t actually influence how the code works. RE_MSG_CODE is actually the code itself like KEY_A or MOUSE_LEFT while RE_MSG_CATEGORY is the category the object has to listen to like RE_MSG_CATEGORY_TOUCH or RE_MSG_CATEGORY_RUNLOOP.

So what is happening here? We have a template class called RESelector which consists of not much but 2 methods and a constructor.
The field variables are a pointer to a target which is the template type. An enum category which is the category the object will listen to, a pointer to a member method from a class of T and an id (or void*) to an object which gets send with the message.
Than we have a std::vector that takes id’s and finally the class REMessageHandler. This class is by no means complete but it will do the job for this tutorial.
We have 2 pointers to vectors in this class. One takes MSG_CODES while the other one is id vector. You will ask, why do we store raw pointers in a vector that should store objects from RESelector? Well, we only need the addresses stored  and because what we will store is actually a template class, we are not able to do: std::vector . We would have to define a std::vector FOR EACH template and this would suck.
The two corresponding messages are straightforward. Both push back stuff on the right vector.
Let’s move on to the most interesting method of this class.
Receiving Messages

void REMessageHandler::evaluateMessages() {
    for (auto it = this->selectorCache->begin(); it != this->selectorCache->end(); ++it){
	RESelector<__tPlaceholder> *selector = (RESelector<__tPlaceholder>*)*it;
	If (selector->getCategory() & RE_MSG_CATEGORY_INPUT) {
            for (auto sec_it = this->msgCache->begin(); sec_it != this->msgCache->end(); ++sec_it) {
	        if (*set_it & RE_MSG_CATEGORY_INPUT) {
		     RE_MSG_CODE code = (RE_MSG_CODE) ((*sec_it) & (~RE_MSG_CATEGORY_INPUT));
		     selector->fire (code);
                }
            }
         …..
    }	
    this->msgCache->clear();
}

Wow.. Looks kinda weird right? I try to explain. We first iterate through the selectorCache which contains all the objects which are registered to listen for events.
As the selectorCache stores only addresses, we need to cast the object to the right type. RESelector is a template class so can’t create a pointer without a type. Of course we want it as generic as possible, so making the method itself a template message is absolutely no option. I came up with the idea to define a struct __tPlaceholder which is just empty. The typedef looks like this

typedef struct __tPlaceholder {} __tPlaceholder

and it’s only purpose is to act as a placeholder. So we create a pointer to an RESelector of type placeholder and assign the value of the iterator to it. Nice!
The next step to check is to what category the selector is listening to. In this example I only implemented RE_MSG_CATEGORY Input so we check if it does and if yes we iterate through all the messages. For each message we check if it is a message for the input category and if yes we fire.
For completeness, this is how a message gets encoded and decoded:

RE_MSG_CODE encoded=(RE_MSG_CODE)(category|code);
#define RE_MSG_INPUT_CODE(__X__) ((__X__)&(~RE_MSG_CATEGORY_INPUT))

With this bunch of code we can now easily make stuff like this


class Foo {
	void mouseCallback(id obj, RE_MSG_CODE msg) {

	     dbgPrint(“I received msg %x from %p”, msg, obj); 
             switch(RE_MSG_INPUT_CODE(msg)){
                 case RE_MSG_MOUSE_INPUT_KEY_UP: {
                     // do s.th.
                     break;
                 }
                 default: break;
             }
        };
}

void Runloop::Init(){
	Foo *foo = new Foo();
        RESelector<Foo> selector = new RESelector<Foo>(foo, &Foo::mouseCallback, this, RE_MSG_CATEGORY_INPUT);
        REMessageHandler::SharedMessageHandler().addEventListener(selector);
}

bool Runloop::Run() {
	REMessageHandler::SharedMessageHandler().evaluateMessages();
        return this->goOn();
}

And every time somewhere gets a input message posted the mouseCallback function in Foo gets called.

Cool? Isn’t it? There are still areas to improve of course but I will leave this to you to figure out what the best approach for your problem is.

Well. That was a huge tutorial and I hope I did an ok job. If you like it I would appreciate a small comment or s.th. 

Greetings
Markus

  1. No comments yet.
  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: