Jump to content
  • Advertisement
Sign in to follow this  
Angelic Ice

Getting rid of void*

This topic is 670 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hello forum!

 

I have a event-listener-system.

 

Example: A window tells the caller-system (who stores listeners and tells whether an event has been triggered) it wants to start listening.

If the caller receives the information of a triggered event, it will notify all listeners to that specific event.

 

Every listener derives from a handler-class for each event they want to listen to.

class Window_Changer : public Event_Handler<Click_Event>

Here is what a window-class calls to register itself:

click_event_listener(event_bus.Add_handler<Click_Event>(*this))

My caller statically casts the this-pointer to a void-pointer that can be stored.

Later, when the listened event has been triggered, I static cast the void-pointer to a Event_Handler<T> and later cast it to what T is.

 

I really want to get away from this C-style of using void-pointers though.

 

Assuming std::function would be a good direction, I'm still a bit rusty in terms of using it.

How could I turn my object into a std::function instead of a void-pointer?

 

To be more precise:

// call from the listener
click_event_listener(event_bus.Add_handler<Click_Event>(*this))

// happening in the Add_handler-method
static_cast<void*>(&object)

Are there certain things to be aware of?

Can I static_cast back from that to a generic Event_Handler<T>, as I did above?

 

Thanks for taking your time : )

Share this post


Link to post
Share on other sites
Advertisement

First, there is nothing bad about using void* in "the right way" to me but you need to use somethign else. Why not let event handlers inherit from certain EventArgs class as it is the thing in C#?

 

Other solution would be a templated class that encapsulates inheritance like "object" does in C# and Java. There is a good tutorial of an object like Any class on CodeProject website https://www.codeproject.com/articles/11250/high-performance-dynamic-typing-in-c-using-a-repla

 

However, I would recomend to use an EventArgs base class so you prevent passed pointers that were not part of your event system

Share this post


Link to post
Share on other sites

The std::function is really nice, code would be something like this: 

void Event_Bus::Add_click_handler(std::function<void(Click_Event)> handler) {
   // save the handler somewhere
}

With no need for special interface classes that you need to derive from, code becomes much cleaner. 

event_bus.Add_click_handler([](Click_Event event) {
   // handle the event here
});

Note that you can capture variables between [ and ] if you need to. 

Edited by Felix Ungman

Share this post


Link to post
Share on other sites

Thanks everyone : )

 

 

 

It sounds to me that you are deriving from a base class, why not cast to that instead of the void*. Added benefit is that you can just call the handle function on these classes, assuming its part of the interface.

 

But how would I cast my Listener with the Handler<Click_Event> base down to Handler<Event_Type>? Click_Event is the template type with the base class of an Event_Type.

Because my registrations would need to store a pointer to that instead of void*, right?

 

Boost seems to have a very neat way of handling this (I wish I would have known before). But it would be weird to rebuild that, as I could just use their library.

(just hoping my way of doing it won't be a performance killer)

Edited by Angelic Ice

Share this post


Link to post
Share on other sites

As others have already stated, std::function is a good solution. But beware if you ever want to implement a remove listener method, because std::function cannot compared to each other. In that case you'll need to resort to some c-style trickery again.

Share this post


Link to post
Share on other sites

But how would I cast my Listener with the Handler<Click_Event> base down to Handler<Event_Type>? Click_Event is the template type with the base class of an Event_Type.
Because my registrations would need to store a pointer to that instead of void*, right?


NightCreature was suggesting that you store references to a list of Handler (note lack of template argument), not Handler<Event_Type>.

Share this post


Link to post
Share on other sites

NightCreature was suggesting that you store references to a list of Handler (note lack of template argument), not Handler.

 

Hm, but my Handler<Event_Type> is my handler. Otherwise, I do not understand what else to store.

As all my Listeners have an inheritances of those. Or should I store a reference to that exact handler?

Share this post


Link to post
Share on other sites

I've become a huge fan of using lambdas and std::function for my events now. 

typedef std::function<void(float, float)> ConfigChangedFunc;
// Method of something that can be listened to:
// All this does is store the std::function in a map
void RegisterForEventConfigChanged(void* reference, ConfigChangedFunc callback)
{
        m_ConfigChangedFuncMap[reference] = callback;
}

// In some object that wants to listen for events:
Window::GetInstance()->RegisterForEventConfigChanged(this,
	[this](float width, float height)
{
	OnConfigChanged(width, height);
});

I pass in the 'this' pointer just as a reference for when I want to unregister events, it is never used beyond this. I remember the bad old days of making event systems without std::function/lambdas and I would hate to go back. Objects don't need to inherit from a base listener class or anything like that; they are far more independent.

Edited by Nanoha

Share this post


Link to post
Share on other sites

 

NightCreature was suggesting that you store references to a list of Handler (note lack of template argument), not Handler.

 

Hm, but my Handler<Event_Type> is my handler. Otherwise, I do not understand what else to store.

As all my Listeners have an inheritances of those. Or should I store a reference to that exact handler?

 

What does the template buy you that a simple Handler class hierarchy would not? 

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!