I am creating a console menu in C++ and I want to give every item in my menu a callback function, so when an item is selected, a different function is called.
So far, I have this code:
#include <iostream>
#include <vector>
using namespace std;
class Core
{
public:
void action1() {}
void action2() {}
//...
};
typedef void (Core::*CoreFunc)();
class Menu
{
struct Option
{
Option(CoreFunc cb) : callback(cb) {}
//some data
CoreFunc callback;
//some more data
};
vector<Option> m_options;
public:
Menu(Core const& core)
{
addOption(core.action1);
}
void addOption(CoreFunc callback)
{
m_options.push_back(Option(callback));
}
void execOptionX(int index)
{
m_options[index].callback();
}
};
int main()
{
Core core;
Menu menu(core);
menu.execOptionX(0);
return 0;
}
Which is giving me this error:
no matching function for call to ‘Menu::addOption(<unresolved overloaded function type>)’
at addOption(core.action1);
and also
must use ‘.*’ or ‘->*’ to call pointer-to-member function in ‘((Menu*)this)->Menu::m_options.std::vector<_Tp, _Alloc>::operator[]<Menu::Option, std::allocator<Menu::Option> >(((std::vector<Menu::Option>::size_type)index)).Menu::Option::callback (...)’, e.g. ‘(... ->* ((Menu*)this)->Menu::m_options.std::vector<_Tp, _Alloc>::operator[]<Menu::Option, std::allocator<Menu::Option> >(((std::vector<Menu::Option>::size_type)index)).Menu::Option::callback) (...)’
when I try to call the function.
I have seen many implementation of member function pointer, but they are all used within the same class.
Why am I getting these errors?
What is the correct syntax to get this code to compile/work?
Thank you
You declared CoreFunc as a non-static pointer-to-member-method. So you need to specify a pointer to the desired method, eg:
addOption(&Core::action1);
More importantly, you also need to provide a Core object instance as the this parameter for the callback. You specify the object via the .* operator (if using an object reference) or the ->* operator (if using an object pointer), eg:
void execOptionX(int index)
{
CoreFunc callback = m_options[index].callback;
(SomeCoreObj.*callback)();
}
void execOptionX(int index)
{
CoreFunc callback = m_options[index].callback;
(SomeCoreObjPtr->*callback)();
}
So, you need to change your Menu class to keep track of the Core object that will be passed to the callback (assuming you don't want to pass the Core object as a parameter to execOptionX(), eg:
class Menu
{
struct Option
{
Option(CoreFunc cb) : callback(cb) {}
//some data
CoreFunc callback;
//some more data
};
Core &m_core;
vector<Option> m_options;
public:
Menu(Core &core)
: m_core(core)
{
addOption(&Core::action1);
}
void addOption(CoreFunc callback)
{
m_options.push_back(Option(callback));
}
void execOptionX(int index)
{
CoreFunc callback = m_options[index].callback;
(m_core.*callback)();
}
};
And of course, the Core object has to remain alive for the lifetime of the Menu (which it does in your main() example).
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
This question is based upon: Calling C++ class methods via a function pointer
What i would like to do is to register a generic object member function to a module lower in the architecture, that can invoke an event callback.
What i need is being able to register any object type (generic), so i do not have to have a registration function for each type of object.
Example from 1:
typedef void(Dog::*BarkFunction)(void);
Then to invoke the method, you use the ->* operator:
(pDog->*pBark)();
Example in my code:
// application layer
class ObjectInHighterLayer
{
ObjectInHighterLayer()
{
xyz::registerEventhandler(this, eventCallback); // ??? how to register here ???
}
void eventCallback(int x)
{
}
}
// middleware layer or hal layer
static clientcallback clientCb = NULL;
namespace xyz {
typedef void (GENERIC_OBJECT_TYPE::*clientcallback)(int /*x*/); // ??? how to define callback type here ???
void registerEventhandler(clientcallback cb);
{
clientCb = cb;
}
void task()
{
// ... if event happend
callClients();
}
void callClients()
{
if(clientCb != NULL)
{
clientCb(3);
}
}
}
There are two patterns I am aware of...
virtual
All the callback functions share a class hierarchy, so a single virtual function can be used to dispatch to the correct type.
class CallbackBase {
public:
virtual void anEvent(int myEvent) = 0;
};
This can be registered by a class directly.
class ObjectInHighterLayer
{
ObjectInHighterLayer()
{
xyz::registerEventhandler(this, eventCallback); // ??? how to register here ???
}
void anEvent(int myEvent)
{
// receive callback
}
}
Or indirectly (probably better to use std::function)
class Test {
public:
void callable(int ) {
}
};
typedef void (Test::*Callable)(int);
This can then be called by a proxy object, separating the hierarchy of the callbacks from that of the called.
class MyFunction {
public:
Callable m_f;
Test * m_Test;
MyFunction( Test * pTest, Callable fn) : m_Test(pTest), m_f( fn )
{
}
void anEvent( int x ) {
(m_Test->*m_f)(x);
}
};
Allowing different functions of test to be registered for different callbacks.
static callback
Change the callback mechanism to take an opaque type. This is easier to code, although sacrifices type-safety.
class Callbackable {
static void callback1( void * pThis, int param )
{
Callbackable *_this = static_cast<Callbackable*>( pThis );
_this->callFunction( param );
}
}
The callback1 because it is static shares a function type with similar functions in different classes (outside of any hierarchy). The idea that it is called with an incorrect pThis is the type safety weakness.
What should I do if I want to pass a non-static member function of any class as a click function of the button ? Is it possible ? If so what do I need to do ? For example in which ever class (EntityToolGUI over here) the button is initiatlized, I want to set its click action to a non-static member function (a non-static member function of class EntityToolGUI ) of that class.
GUIButton.h
typedef void (*ptr2clickFunc)(void);
class GUIButton : public GUIObject {
private : void (*clickFunc)(void);
public : void setClickFunction(ptr2clickFunc clickFunc);
};
GUIButton.cpp
void GUIButton::setClickFunction(ptr2clickFunc clickFunc)
{
this->clickFunc = clickFunc;
}
EntityToolGUI.h
class EntityToolGUI {
public : EntityToolGUI();
protected : void addAnimation();
}
EntityToolGUI.cpp
void EntityToolGUI::addAnimation()
{
cout<<"add animation"<<endl;
}
EntityToolGUI::EntityToolGUI()
{
....
btnAddAnimation->setClickFunction(&EntityToolGUI::addAnimation);
}
I am getting an error no matching function call to GUIButton::setClickFunction(void (EntityToolGUI::*)())
candidate is void GUIButton::setClickFunction(void (*)())
How do I solve this ?
Most (decent) C code that passes function pointers around use an extra void* argument for passing user context to the function. This is not so common in C++ (as better techniques than function pointers exist), but if you're stuck using function pointers for some reason then it may be appropriate.
typedef void (*ptr2clickFunc)(void*);
class GUIButton : public GUIObject {
private : ptr2clickFunc clickFunc;
private : void * userdata;
public : void setClickFunction(ptr2clickFunc clickFunc, void* userdata);
};
class Foo
{
static void do_foo( void * userdata )
{
Foo* thisptr = static_cast<Foo*>(userdata);
thisptr->foo();
}
void foo() { ... }
};
int main()
{
Foo foo;
GUIButton button;
button.setClickFunction( &Foo::do_foo, &foo );
button.click();
}
EDIT As noted by Bartek, if you're doing this a lot you can extract the static function into a template - it looks a bit like this (untested and probably with minor errrors).
// GUIButton is as before
// Note no static function here
class Foo { void foo(); }
template<typename T, void(T::*FN)() >
void Call( void * data)
{
static_cast<T*>(data)->*FN();
}
int main()
{
Foo f;
GUIButton button;
button.setClickFunction( &Call<Foo,&Foo::foo>, &f );
button.click();
}
If you want to pass obj fun ptr you can use boost::bind and boost::function
http://www.boost.org/doc/libs/1_50_0/libs/bind/bind.html
You cannot pass a pointer to non-static member function as a pointer to a "regular" non-member function. You should either make addAnimation static, or make ptr2clickFunc typedef a pointer to member function.
Note that invoking a pointer to member function is different from invoking a function pointer, because you must supply an instance on which the member pointer is to be invoked.
addAnimation needs to be static function. When the call back function is set the way you are doing it now, the object of class EntityTollGUI is not registered along with the function.
Try this one (C++11):
#include <stdio.h>
#include <stdlib.h>
#include <functional>
class Raiser
{
public:
std::function<void(int)> ev1, ev2;
void RaiseEv1()
{
if (!ev1._Empty())
ev1(44);
}
void RaiseEv2()
{
if (!ev2._Empty())
ev2(66);
}
};
class Handler
{
private:
int id;
std::function<void(int)> h;
public:
Handler(int newId)
{
id = newId;
h = [this](int i)
{
printf("Handler with id = %d captured event!\n", this->GetId());
};
}
void Hook1(Raiser & raiser)
{
raiser.ev1 = h;
}
void Hook2(Raiser & raiser)
{
raiser.ev2 = h;
}
int GetId()
{
return id;
}
};
int main(int argc, char * argv[])
{
Raiser raiser;
Handler handler1(1), handler2(2);
handler1.Hook1(raiser);
handler2.Hook2(raiser);
raiser.RaiseEv1();
raiser.RaiseEv2();
getchar();
}
AFAIK, this is the most you can get with events in C++ without using language extensions.
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);
...
class Action {
public:
void operator() () const;
}
class Data {
public:
Data();
~Data();
Register(Action action) { _a = action; }
private:
Action _a;
}
class Display {
public:
Display(Data d) { d.Register( bind(Display::SomeTask, this, _1) ); }
~Display();
void SomeTask();
}
I want to bind the private member _a of Data to a member function of Display, but I get compile errors saying my argument types don't match when I call d.Register, what am I doing wrong? Thanks.
What you're trying to do is not completely clear, but I'll assume that "bind" is boost::bind (or tr1::bind).
A couple of problems with bind(Display::SomeTask, this, _1):
It should be &Display::SomeTask
The _1 placeholder makes no sense because that creates an unary function object and:
Display::SomeTask takes no arguments
Action::operator() takes no arguments
Using Boost.Function and Boost.Bind, here's what you could write to acheive what I guess you're trying to do:
typedef boost::function<void(void)> Action;
class Data {
public:
Data();
~Data();
Register(Action action) { _a = action; }
private:
Action _a;
};
class Display {
public:
Display(Data d) { d.Register( bind(&Display::SomeTask, this) ); }
~Display();
void SomeTask();
};
I cannot see what 'bind' returns, but I absolutely sure this is not compatible with Action class. Also you are using 'copy semantic', so if Action has empty implmentation, you will never get desired.
Try change Register(Action* action), and allow 'bind' to return some child of Action class.
Also review possibility to migrate to templates - than you even can exclude Action class at all
template <class A>
class Data { ...
Register(A action)...
A _a;
...
In this case you could be able to use as classes with overridden operator() as functions without argument.
First, you have to use &Display::SomeTask and give Register a return type, and then it depends on your needs
The wrapper should call SomeTask on *this: Omit _1.
The wrapper should call SomeTask on a passed Display object: Shift _1 in place of this.
Then, boost::bind returns some complicated synthesized type that will call the specified function. You need a way to store it, which is where boost::function comes handy. This is how you can do it
class Display; // forward-declaration
class Data {
public:
Data();
~Data();
template<typename Action>
void Register(Action action) { _a = action; }
private:
boost::function<void(Display&)> _a;
// if wrapper should call it on `*this`
// boost::function<void()> _a;
}
class Display {
public:
// this currently makes no sense. You pass a copy. Probably you
// should consider pass-by-reference or processing "d" further.
Display(Data d) { d.Register( bind(&Display::SomeTask, _1) ); }
// wrapper should call it on `*this`:
// Display(Data d) { d.Register( bind(&Display::SomeTask, this) ); }
~Display();
void SomeTask();
}
Then it should work.