C++ Passing a member function as a callback - c++

I am trying to create a very simple event system to be used in a game. I have a EventManager class that looks something like this:
typedef std::function<void(IEvent* event)> CallbackType;
class EventManager
{
public:
void AddListener(const std::string eventName, IEventListener* listener)
{
CallbackType callback = std::bind(&IEventListener::HandleEvent, listener, std::placeholders::_1);
listeners[eventName].push_back(callback);
}
void AddListener(const std::string eventName, CallbackType callback)
{
// ...
}
void TriggerEvent(IEvent* event)
{
for (CallbackType callback : listeners[event->GetName()])
{
callback(event);
}
}
private:
std::map<std::string, std::vector<CallbackType>> listeners;
}
The 1st AddListener function works perfectly. The TriggerEvent function calls the HandleEvent function, which is implemented by each class that extends my IEventListener interface.
I would really like to be able to pass a callback to the 2nd AddListener function. This callback would then get called in the TriggerEvent function as before. I can pass in a callback constructed using std::bind and this works. For example:
eventManager->AddListener("WindowResize", std::bind(&MyClass::MemberFunction, this, std::placeholders::_1));
where MyClass extends the IEventListener interface. However, I'd really like to be able to just pass a simple function pointer instead:
eventManager->AddListener("WindowResize", this, &MyClass::MemberFunction);
Is this possible?
Edit
For anyone interested, I wrote a couple of macros that I think makes things a little cleaner.
#define MEMBER_CALLBACK(funPtr) \
std::bind(&funPtr, this, std::placeholders::_1)
#define MEMBER_CALLBACK_WITH_INSTANCE(funPtr, instancePtr) \
std::bind(&funPtr, instancePtr, std::placeholders::_1)
Now I can subscribe to an event by:
eventManager->AddListener("EventName", MEMBER_CALLBACK(MyClass::MemberFunction));

You can't pass a simple function pointer because MyClass::MemberFunction isn't a simple function. The std::bind() works because it associates an instance of MyClass with the reference to the member function. Without that information, the member function would not have access to the instance's data.

Related

Pass argument to function taking parent class argument without casting argument to parent class

I am building a Boost state machine. My state has a pointer to its own backend (fsm) to process events. All events of my state machine are children of an MySatetMachineEvent class (with an example child like EventChild). State transitions are only defined for children like EventChild of MySTateMachineEvent.
To clean up my code I want to create a function processEvent(MySatetMachineEvent event) taking all possible events. This class should then call the process_event() function with the passed event.
For example:
processEvent(MyStateMachineEvent event)
{
fsm.process_event(event);
}
processEvent(EventCild());
should case a call of
fsm.process_event(EventChild());
Creating such a function causes the error that fsm.process_event() is called with an instance of MyStateMachineEvent. As written above there are no state transitions defined for this case.
This hinders my state machine from working in a proper manner, obviously.
So my question is if there is a way to pass any EventChild or other child of MyStateMachineEvent to my processEvent(MySTateMachineEvent event) function without casting the passed Object to MyStateMachineEvent.
I am aware of the solution to overlode my function like
processEvent(EventChild event) {
fsm.process_event(event);
}
This would cause may functions (with the exact same line of code inside) in my case, thus i am looking for a cleaner and more fancy solution.
You can use a function template:
template <typename Event>
void processEvent(Event event)
{
fsm.process_event(event);
}
Every instantiation will preserve the exact type of the event argument that was passed in.
Albeit I like Vittorio Romeo's template approach, it might not be suitable if you e. g. have some kind of event queue holding arbitrary events. A polymorphic approach could be more suitable then:
class MyStateMachineEvent
{
public:
virtual ~MyStateMachineEvent() { }
virtual void doOrGetSomething() = 0;
};
class EventChild : public MyStateMachineEvent
{
public:
void doOrGetSomething() override;
};
Now your processEvent function might accept a reference, just as would the fsm's variant as well:
void processEvent(MyStateMachineEvent& event)
{
fsm.processEvent(event);
}
void FSM::processEvent(MyStateMachineEvent& event)
{
// ...
event.doOrGetSomething();
// ...
}
And usage might look like this:
std::queue<std::unique_ptr<MyStateMachineEvent>> events;
events.emplace(new EventChild());
processEvent(**events.front());
events.pop();

How do I convert V8 objects to pointers?

I'm writing a Node application (in TS) that needs to be interfaced with some native library.
I have a library (written in C) - let's consider it's a blackbox - and I'm writing a wrapper using NAN. The library native interface can be simplified into a following functions:
typedef void (*got_message_reply_cb)(context ctx, void * priv, struct X * the_reply);
context lib_connect();
bool lib_send_message(context ctx, message msg, got_message_reply_cb callback, void * priv);
I believe this is pretty straight-forward to understand.
So, I'm trying to wrap that black-box native library into something like:
class TheLibrary : public Nan::ObjectWrap {
Initialize(v8::Handle<v8::Object> target);
SendMessage(...)
}
And then to javascript object like:
class TheLibrary {
SendMessage(message: whatever, callback: (reply) => void); // or return promise, doesn't matter
}
How to do the actual handling of the callback in the NAN C++ module? I need to somehow pass the callback (represented probably by Local<Function> - which have, if I understand it correctly, limited scope) as a pointer to the function and then retrieve it back. How to do that? Thanks for your replies.
The high level answer is that you don't pass the JS callback function directly, but pass in a pointer to a function that somehow has your JS callback as a context value (in your example the priv parameter).
So for your case you write something like this:
void TheLibraryCallback(context ctx, void *instance, struct X *the_reply) {
((TheLibrary*)instance)->callback(ctx, the_reply);
}
In your TheLibrary you add a method void callback(context ctx, struct X * the_reply) that handles the callback. You call your library like this: lib_send_message(ctx, msg, TheLibraryCallback, this); with this being a TheLibrary instance.
So how do you call back the JS callback in your callback method? With nan you will have to make sure you are back in the main thread. There are examples out there, but I would suggest that you use the new N-API instead. The AsyncWorker helps with the boilerplate that you need to do to call the callback in the main thread.

Calling C++ method with callback from ObjectiveC

I need to call a C++ method and pass in a callback method as a parameter... from ObjectiveC method...
This callback method would then be triggered multiple times in ObjectiveC... as it's a callback... and so then I need to trap that ObjectiveC callback method back as it will be called as a closure from Swift code...
This is the C++ Method Signature
static bool cPlusPlusMethodWithCallBack(const std::string& someText, void (*someCallback)(unsigned int) = NULL, unsigned int someNum = 0);
My Question is what should be the Block syntax of this Callback Method declared in ObjectiveC (in .mm and .h) which can then be passed as a parameter to this someCallback in C++
I am a Swift developer so bit stuck on ObjectiveC... Many Thanks
You can't pass an Objective-C block (or a Swift closure) as a function pointer argument like that. You'll need to create a separate, standalone function, and pass that in as the callback.
void MyCallback(unsigned int value)
{
// ...do something...
}
And in your main code:
cPlusPlusMethodWithCallBack("something", MyCallback);
Now, the downside of this is that in your callback, you'll often need to reference a particular Objective-C object in order to properly handle the callback. If that's something you need with this particular callback, you'll need to save it off somewhere as a static variable so that it can be accessed from the MyCallback function.
Alternatively, if you have control over the cPlusPlusMethodWithCallBack source code, you can update it to take a void * "reference" parameter, and then supply that parameter as an argument when you call the callback:
static void cPlusPlusMethodWithCallback(void (*callback)(void *ref), void *ref)
{
// ...really time consuming processing...
callback(ref);
}
Then, update your callback function:
void MyCallback(void *ref)
{
ObjectiveCObject *obj = (ObjectiveCObject *)ref;
[obj doSomething];
}
And when you initially call the method, just pass in the object you need as the reference parameter:
cPlusPlusMethodWithCallback(MyCallback, myObjectiveCObject);

Handling events raised from a lower level object

I'm writing a C++ programm using GTK+3.0. Anyway, I think this question may apply to any framework that uses events / signals.
I have a container class, say containerClass and a child class, say childClass. A childClass object child is contained inside a containerClass object container.
The child object is written to modify properties of something. To this aim, it has GtkEntry, GtkButton and so on. When I click the "save button", an event is raised.
This event must be handled by the container object, because the container is interfaced with a database in someway.
Hereafter, you find the solution I'm using to do the job:
// Child class
class childClass {
void setClickHandler_External(void (*extFun)(string property), void *);
void (*clickHandler_External)(string, void *);
void *clickHandler_External_Data;
static void buttonClicked(GtkWidget *widget, void *data);
}
void childClass::setClickHandler_External(void (*extFun)(string), void *data) {
// Set the external event handler
clickHandler_External = extFun;
clickHandler_External_Data = data;
}
void childClass::buttonClicked(GtkWidget *widget, void *data) {
childClass *m = (childClass *)data;
// Call the external event handler
m->clickHandler_External(property, m->clickHandler_External_Data);
}
// Container Class
class containerClass {
childClass child;
static void clickHandler(string property, void *data);
}
containerClass::containerClass() {
// Set the event handler
child.setClickHandler_External((void(*)(string))&(this->clickHandler), (void *)this);
}
void containerClass::clickHandler(string property, void *data) {
// Event handler in the upper class
containerClass *m = (containerClass *)data;
//FINALLY, DO THE JOB WITH PROPERTY!!!
}
This works well and does the job. Anyway, I was wondering if there is a smarter and cleaner way to achieve the same aim, maybe without using pointers to static functions, or by defining some kind of pattern to be reused everytime I need to have the same mechanism.
Thanks in advance
Gtkmm uses the sigc++ library to take care of all of this for you. There is no need to write it yourself.
Documentation links:
Signals overview
Appendix with detailed information
So, in this case, I would use something like
button.signal_clicked().connect(sigc::mem_fun(container, &containerClass::clickHandler));
while making sure that containerClass::clickHander has the appropriate number of arguments.
My first suggestion would be to use use templates to improve the type safety of what you are doing:
template< class ParamType >
void childClass::setClickHandler_External(void (*extFun)(string, ParamType *),
ParamType *data)
{
// Set the external event handler
clickHandler_External = (void ()(string,void*))extFun;
clickHandler_External_Data = (void*)data;
}
Then you can simplify the containerClass implementation as such:
// Container Class
class containerClass {
childClass child;
static void clickHandler(string property, containerClass *data);
}
containerClass::containerClass() {
// Set the event handler
child.setClickHandler_External(&containerClass::clickHandler, this);
}
void containerClass::clickHandler(string property, containerClass *data) {
//FINALLY, DO THE JOB WITH PROPERTY!!!
}
While it's great that this cleans up the implementation, removing the explicit casting from all the container implementors, that's not really the point. The point is to prevent you from passing wrong pointers into setClickHandler_External, causing crashes on the back end when events get dispatched.
My next step would take us further from your implementation, but would require more details about what you are actually doing. Depending on your needs that would be looking into:
Inheritance: should containerClass derive from childClass? That would provide access to a virtual function table that we could override.
Functors: look at boost::function and boost::bind to implement functors, eliminating the intermediate static function call.
Lambda Functions: bleeding edge (C++11 or later), but may be a good fit for this kind of forwarding function.

Storing Lua callback functions

I have a game I am integrating with Lua scripting in order to allow customization.
I am using a C++ Lua wrapper:
https://github.com/tomaka/luawrapper
In my Lua script I am calling something like this:
function sprite_factory()
local sprite = sprite_new() -- register_new_sprite(name)
sprite:RegisterCallback("on_activate", function ()
sprite:SetState("closed")
end)
end
In my C++ code I have built a Sprite class and I'm using registerFunction to make the member methods available to Lua e.g. RegisterCallback is called on the sprite object returned by sprite_new()
bool RegisterCallback(const std::string hook, const std::function<void()> callback) {
callback();
mCallback = callback;
return true;
}
If I do the callback inside the RegisterCallback method, it works fine. However, I want to store the callback to be used as a raised event.
When I call this method later in my code:
void DoCallback() {
mCallback(); //raises exception
}
I get an exception:
libc++abi.dylib: terminating with uncaught exception of type
std::__1::bad_function_call: std::exception
I am declaring mCallback as a private:
std::function<void()> mCallback = NULL;
I'm not sure what is going on here.
I would suspect that there is an issue with the way mCallback is declared.