I have a problem now. I am trying to encapsulatie boost::signal and boost::bind into my own Event class.
class MyEvent
{
private:
boost::signal<void ()> Sig;
public:
void Subscribe(.........)
{
Sig.connect(boost:bind(.........);
}
void Raise()
{
Sig();
}
};
I have try to pass function pointer in the Subscribe function's signature and visual studio just gives me tones of errors.
I dont know how to write the signature of Subscribe and What to pass into boost::bind, ideally I will have boost::bind(&MyClass::MyHandler, &MyClassObject) in Subscribe function and will Call it outside like MyEventObject.Subscribe(&MyClass::MyHandler, &MyClass).
Can any people help me fill that two blanks?
You can just make Subscribe a template:
#include <boost/signals2.hpp>
#include <boost/bind.hpp>
class MyEvent
{
private:
boost::signals2::signal<void ()> Sig;
public:
template<class SlotClass>
void Subscribe(void (SlotClass::*func)(), SlotClass *obj)
{
Sig.connect(boost::bind(func, obj));
}
void Raise()
{
Sig();
}
};
struct Test
{
void f()
{}
};
int main()
{
MyEvent myEvent;
Test test;
myEvent.Subscribe(&Test::f, &test); // test must outlive myEvent!
}
Note however that such a wrapper limits its user very much: with original signal he could connect any callable of any kind created in various ways, while with your wrapper he must pass a pointer to member function and a pointer to object.
Related
I'm trying to give a method as a callback of another method just like that:
Actions actions;
Button button;
int main()
{
actions = Actions();
button = Button();
button.onClick(actions.doSmthg);
return 0;
}
Here is my Actions:
class Actions {
public:
Actions();
void doSmthg();
};
and here is the Button with my attempt of implementing a callback pattern:
class Button {
public:
Button() {};
void onClick(void (*callbackPtr)());
};
Sadly I got the following error:
error: invalid use of non-static member function ‘void Actions::doSmthg()’
I've check multiple examples that suggest to use std::bind when dealing with callbacks but I'm really not sure how to make it work.
Any idea to implement such a pattern in C++?
Here is a live sandbox https://onlinegdb.com/nL3SIUOaI.
Method 1
You can make use of std::bind and std::function as shown below:
#include <iostream>
#include <functional>
class Actions {
public:
Actions(){}
void doSmthg(){
std::cout<<"do something called"<<std::endl;
}
};
class Button {
public:
Button() {};
void setFunc(std::function<void ()> eventFunction) { fn = eventFunction; }
void onClick(){
std::cout<<"button clicked"<<std::endl;
//call the function on the passed object
fn();
}
private:
std::function<void ()> fn;
};
int main()
{
Actions action;
Button button;
button.setFunc(std::bind(&Actions::doSmthg, action));
button.onClick();
return 0;
}
The output of the above program can be seen here:
button clicked
do something called
Method 2
Here we make the onClick member function to be a member function template.
#include <iostream>
class Actions {
public:
Actions(){}
void doSmthg(){
std::cout<<"do something called"<<std::endl;
}
};
class Button {
public:
Button() {};
template<typename T>
void onClick(void (T::*callbackPtr)(), T obj){
std::cout<<"button clicked"<<std::endl;
//call the function on the passed object
(obj.*callbackPtr)();
}
};
int main()
{
Actions action;
Button button;;
button.onClick<Actions>(&Actions::doSmthg, action);
return 0;
}
The output of the above program can be seen here:
button clicked
do something called
I would like to have the following class setup in a program:
A class that implements a buffer. This buffer, when full, would spawn a thread that makes a callback to handle what to do with the full buffer.
A class that includes a buffer object. Implements the callback function.
I'm having some trouble spawning the std::thread that runs the callback. It seems like I'm getting its parameters wrong, but I can't figure it out.
The minimal reproducible example:
#include <thread>
class MyClass;
class CallbackClass
{
public:
void (MyClass::*callback)();
std::thread a_thread;
void setCallback(void (MyClass::*cb)())
{
callback = cb;
}
void writeCall()
{
a_thread = std::thread(callback); // error here
}
};
class MyClass
{
public:
CallbackClass callbackobject;
MyClass()
{
callbackobject.setCallback(&MyClass::bufferWriter);
}
void bufferWriter(){}
};
int main(){}
The compiler error I get:
error: no matching function for call to ‘std::thread::_Invoker<std::tuple<void (MyClass::*)()> >::_M_invoke(std::thread::_Invoker<std::tuple<void (MyClass::*)()> >::_Indices)’
operator()()
on this line:
a_thread = std::thread(callback); // error here
void (MyClass::*callback)();
This is a pointer to a class method.
a_thread = std::thread(callback);
A class method is not a function that can be called by itself. The class method requires an object for which it gets invoked. You need to store, or obtain a pointer to a MyClass object, from somewhere. For example, you can pass a 2nd parameter to `setCallback:
void setCallback(void (MyClass::*cb)(), MyClass *ptr)
and then stash it away, somewhere, then use it to invoke the class method. Typically, this would be something like:
a_thread = std::thread(callback, ptr);
So basically I'm making buttons in a game, and the buttons are a called Button.
The class i want the function from to store is called SoccerLevelsClass. I've tried looking into function pointers, but I'm not sure what's going on though i think it's the correct thing to do.
I want to save the function of SoccerLevelsClass as a member of Button.
Would i do something like this?
//MenuButton.h
#ifndef MenuButton
#define MenuButton
....
class Button
{
public:
Button(void(*SoccerLevelsClass::func)());
void (*SoccerLevelsClass::function)();
....
}
#endif
//MenuButton.cpp
#include <MenuButton.h>
Button::Button(void(*SoccerLevelsClass::func)())
{
function=func; //something like this
}
I know the code is probably way off, but I'd like to know if anybody has any suggestions.
All i really want to know is if it's possible.
Yes, this can be done - either with function pointers like in your example, or with lambdas if you can use C++11.
However, since you want to call a bound function of another class, you would need to pass/store pointer to an instance of that class as well to do that, unless the function is static.
In C++11, this is trivial:
std::function<void(void)> _f;
void apply() {
_f();
}
Bar(void (Foo::* f)()) {
_f = std::bind(f, Foo());
}
In C++03, this is a little tricky. Note in both versions I construct a temporary to call the member function, but I'm not sure whether it is necessary to store an instance of the class.
#include <iostream>
#include <functional>
struct Foo
{
Foo() { }
void stuff() {
std::cout << "hi\n";
}
};
struct Bar
{
void (Foo::* _f)();
void apply() {
(Foo().*_f)();
}
Bar(void (Foo::* f)()) {
_f = f;
}
};
int main()
{
Bar bar(&Foo::stuff);
bar.apply();
}
For what you are trying to do I would use the observer pattern:
class IFootballObserver
{
public:
virtual void OnBallKicked() = 0;
virtual ~IFootballObserver() {}
};
class Fooball
{
public:
Fooball(IFootballObserver& obs)
: mObs(obs)
{
// Call the observer interface at any time like so:
mObs.OnBallKicked();
}
private:
IFootballObserver& mObs;
};
class Button : public IFootballObserver
{
public:
// Football could be passed in/owned by something else
Button() : mFootball(*this) { }
void DoSomething()
{
// Called when foot ball is kicked
}
private:
virtual void OnBallKicked()
{
DoSomething();
}
Fooball mFootball;
};
I find this easier than using function pointers/std::function. Plus you could have a vector of observers and notify many objects of events.
I have a question regarding callbacks using tr1::function. I've defined the following:
class SomeClass {
public:
typedef std::tr1::function<void(unsigned char*, int)> Callback;
void registerCallback(Callback);
private:
Callback callback;
}
I've defined another class:
class SomeOtherClass {
void myCallback(unsigned char*, int);
}
Now I want to register my function 'myCallback' as callback at class 'SomeClass'using the method 'registerCallback'. However, it is not working. I've had a look on the boost documentation on the function and it seems legit to use (member) methods of a class for callbacks. Am I wrong?
Thanks in advance!
Member functions have an implicit first parameter, a this pointer so as to know which object to call the function on. Normally, it's hidden from you, but to bind a member function to std::function, you need to explicitly provide the class type in template parameter.
#include <functional>
#include <iostream>
struct Callback_t {
void myCallback(int)
{
std::cout << "You called me?";
}
};
class SomeClass {
public:
SomeClass() : callback() { }
typedef std::function<void(Callback_t*, int)> Callback;
// ^^^^^^^^^^^
void registerCallback(const Callback& c)
{
callback = c;
}
void callOn(Callback_t* p)
{
callback(p, 42);
}
private:
Callback callback;
};
int main()
{
SomeClass sc;
sc.registerCallback(&Callback_t::myCallback);
Callback_t cb; // we need an instance of Callback_t to call a member on
sc.callOn(&cb);
}
Output: You called me?;
Why all this complicated mumbo-jumbo?
Why not create a class as thus (for example)
Class MouseOverEventCallBack
{
public:
virtual void RunMouseOverCallback() = 0;
};
Then just create classes that inherit this class (and redefine the method RunMouseOverCallback)
Then Register function just needs to be
void registerCallback(MouseOverEventCallBack *callbackObject); // possible could use a reference
The register method will just call the method and the object will have all that it needs.
Seems a bit simpler. Let the compiler do the work with pointers to functions etc.
the function void (*)(unsigned char*, int) is a free function, which is a different type from void (SomeOtherClass::*)(unsigned char*, int), thus the error. You need an object to call the latter, while the former is a free function.
Look at the possible solutions listed in the Boost documentation
Another possibility is that your SomeOtherClass::myCallback is private, so you do not have access to it.
Use templates:
template <class T>
class B
{
public:
typedef void (T::*TCallBackFunction)(void);
void SetCallBack(T* pCallBackClass, TCallBackFunction pCallBackFunction)
{
if(pCallBackFunction && pCallBackClass)
{
m_pCallBackFunction = pCallBackFunction;
m_pCallBackClass = pCallBackClass;
}
}
void StartCallBackFunction()
{
(pCallBackClass->(*m_pCallBackFunction))();
}
private:
TCallBackFunction m_pCallBackFunction;
T* m_pCallBackClass;
};
Such like this. And use it:
...
B<MyClass> b;
b.SetCallBack(&b, &MyClass::MyFunction);
...
So I'm working on this event management class. I'm storing a list of pointers to member functions of the signature void (Event*) where Event is just a struct that stores some random data at the moment.
typedef boost::function<void(Event*)> Callback;
typedef vector<Callback> CallbackList;
class EventManager
{
public:
template<typename T>
void RegisterEventHandler(const std::string& type, void (T::*handler)(Event*), T* obj)
{
mCallbackList[type].push_back(boost::bind(handler, obj, _1));
}
void DispatchEvent(const std::string& type, Event* evt)
{
for(CallbackList::iterator it = mCallbackList[type].begin(); it != mCallbackList[type].end(); ++it)
{
Callback callback = (*it);
callback(evt);
}
}
private:
hash_map<std::string, CallbackList> mCallbackList;
};
I'm wondering, if it's possible for me to derive different versions of Event, and pass pointers to those member functions into this class? Currently I'm trying this.
class MouseEvent : public Event
{
public:
int testMouseData1;
int testMouseData2;
int testMouseData3;
};
class HelloWorld
{
public:
void Display(MouseEvent* evt)
{
cout << "Hello, world!" << endl;
}
};
int main(void)
{
MouseEvent* evt = new MouseEvent();
HelloWorld* world = new HelloWorld();
eventManager->RegisterEventHandler("testType", &HelloWorld::Display, world);
return 0;
}
This gives me the following error in XCode.
error: no matching function for call to 'EventManager::RegisterEventHandler(const char [9], void (HelloWorld::*)(MouseEvent*), HelloWorld*&)'
Do you know how I can safely pass in a pointer that's expecting a derived class in its function signature? Thanks.
So I found a solution that seems to be working for me, but I'm not sure if it's entirely safe to do. I changed the RegisterEventHandler method to cast all of the function pointers that I send in to the same type...
template<typename T1, typename T2>
void RegisterEventHandler(const String& type, T1 handler, T2* obj)
{
void (T2::*evtHandler)(Event*) = (void (T2::*)(Event*)) (handler);
mCallbackList[type].push_back(boost::bind(evtHandler, obj, _1));
}
now it all seems to just work as I originally intended. But I'm pretty new to all this so I'm not entirely sure if this is a safe thing to do. Any thoughts? Thanks
If your prototype expects "Event" type then you need to make sure the void Display(MouseEvent* evt) function is accepting the "Event" type. So change it to void Display(Event *evt) Then inside the call you can typecast it back to a MouseEvent, assuming that the caller passed an actual MouseEvent, referenced as an "Event".
Secondly, I believe you may have some other issues with the way you are calling RegisterEventHandler since it is in a template but you are not specifying the template type.