I began implementing my GUI system for my game last night and I decided to try using function pointers to handle gui events. I haven’t used them before, but was able to get a basic implementation in. However, I want to extend the usability and ‘genericness’ of the GUI system. Currently I have a function pointer in the GUI superclass under the protected modifier. I also have a getter (callback) and a setter (subscribeEvent) in the class to assign the gui an event. It currently looks a little something like this:
class GUI
{
public:
…….
……
std::function<void()> callback() const { return eventCallback; }
void subscribeEvent(const std::function<void()>& callback)
{
eventCallback = callback;
}
protected:
std::function<void()> eventCallback;
};
To set a function callback, you pass in a void function to subscribeEvent which works fine. However you cannot use a scope resolution modifier with any function, the function passed in has to be a global function like so.
(MainGame.h):
void global();
class MainGame
{
public:
void Init();
void nonGlobal();
private:
std::vector<GUI*> _guis;
};
(MainGame.cpp):
void MainGame::Init()
{
Button* button = new Button(……); //< Button is a subclass of GUI
button->subscribeEvent(global); //< This works fine
button->subscribeEvent(MainGame::nonGlobal); //< This does not work saying something like “void(MainGame) is not of type void()”
_guis.pushBack(button);
}
void MainGame::nonGlobal()
{
……
}
void global()
{
……
}
Does anyone know how to modify the parameter to allow any function in the scope of any class to be passed in. This would be helpful because I could have a button event come from a player, enemy, item, etc class and not have every handler function be global. I’ve seen high level gui systems pass in events such as ‘event(handlerFunction, classtype)’ so you can pass in the handler function and then an object that the handler function resides in. This is an approach I would like to take.
Your code would work if you made the function MainGame::nonGlobal static:
class MainGame
{
public:
void Init();
static void nonGlobal();
private:
std::vector<GUI*> _guis;
};
The reason you can't pass a non-static member function is because member functions have an implicit first parameter (this), in your case of type MainGame*. So in effect the function you're currently trying to pass has the signature void(MainGame*) instead of void().
Alternatively, you can bind the this parameter by using a lambda instead of passing the function directly:
button->subscribeEvent([this](){nonGlobal();});
Change this:
button->subscribeEvent(MainGame::nonGlobal); //< This does not work saying something like “void(MainGame) is not of type void()”
to
button->subscribeEvent(std::bind(&MainGame::nonGlobal, this));
With this change you have another problem of lifetime management of this though.
Related
I'm writing a C++ application on top of a C HAL for an embedded systems. I need to call an object method from a peripheral C handler but I'm having the following issue:
The peripheral ISR handler I pass to the HAL has a fixed signature. Because of that I can't pass a public method of a C++ object because of the implicit parameter this. In the handler I don't have any reference to the object.
One solution could be to make this object singleton to have a global acces to it but for any reason I may don't want it.
What can I do?
A plain C++ member function can never be an ISR. It has to be a static member function. Indeed you have to do some manner of singleton design. There is no need to make anything "global" though.
This is not unique to ISRs but the same applies to any callback function.
My first thought is to have a method pointer variable that is settable and the ISR calls that method pointer if it is set.
This is untested, uncompiled code, but shows how I would start:
void (*Object::Method)() IsrMethod;
// call this to set the method that will be called. Maybe pass
// in the method pointer of a specific object.
void SetIsrMethod()
{
IsrMethod= someObject.someMethod;
}
void ISR()
{
// if the method is valid, call it.
if( IsrMethod!= null )
{
IsrMethod();
}
}
This also assumes that the object is valid and not deleted.
Class MyObj
{
public:
void doIsr()
{
// Handle ISR.
}
static void HandleIsr()
{
MyObj* isrObj = getRelevantObject(); // Whatever object you like to call to.
isrObj.doIsr();
}
}
If you want to register a specific object to the isr, you can do it like so:
Class MyObj
{
public:
void doIsr()
{
// Handle ISR.
}
static void HandleIsr(MyObj* obj)
{
obj.doIsr();
}
}
And when you register to the ISR, you need to pass obj as a parameter.
I'm fairly new to the concept of function pointer in C++, so I don't know how to write my question properly. Please bear with me.
Basically, what I'm trying to do is to create a Button object whose constructor accepts a function pointer as its parameter. That function pointer points to a function which will change state of the StateMachine.
Here is the sample code (it doesn't work, and irrelevant bits have been stripped out)
Button.h
#include "StateMachine.h"
class Button
{
private:
void (*m_onclickAction)(); //a data member
public:
Button(void (*action)());
};
StateMachine.h (I didn't write it, I just use it with permission. So there should be no problem with the code, and I don't want to modify it)
#include <map>
template<class E, class T>
class StateMachine
{
public:
typedef void (T::*CallbackOnInitialise)();
typedef void (T::*CallbackOnExit)();
private:
T* m_pOwner;
E m_currentState;
// Maps to store function pointers to state functions.
std::map<E, CallbackOnInitialise> m_statesOnInitialise;
std::map<E, CallbackOnExit> m_statesOnExit;
public:
StateMachine(T* pOwner, E emptyState)
{
m_currentState = emptyState;
m_pOwner = pOwner;
}
void ChangeState(E statenext)
{
//do something to change the state
}
};
So that in my main Program class, I could be able to do something like this
#include "Button.h"
#include "StateMachine.h"
//Code to instantiate an StateMachine object goes here
Button* aButton = new Button(aStateMachine->ChangeState(NEW_STATE));
The problem is I can't think of a way to correctly pass the NEW_STATE, which is an enum declared in the Program class as the function pointer is expecting no parameter. I have tried tweaking around with it, but no success.
Any suggestion on how should I do it?
You have a couple of problems here. The first is that in your version you call the ChangeState member function when you create the Button instance. The second is that m_onclickAction is a pointer to a function, which is not the same as a pointer to a member function.
For this I suggest you look into std::function and std::bind:
class Button
{
std::function<void(int)> m_onclickAction;
public:
Button(std::function<void(int)> action) { ... }
};
Then you can create your button like this:
Button* aButton = new Button(
std::bind(&StateMachine::ChangeState, aStateMachine, NEW_STATE));
For callbacks boost::bind() and boost::function() is a very useful tool. So your Button class may look like this:
class Button
{
public:
typedef boost::function<void()> Callback;
Button( Callback clickAction );
private:
Callback m_onclickAction; //a data member
};
Code to pass StateMachine method with parameter then would be:
Button* aButton = new Button( boost::bind( &StateMachine::ChangeState, aStateMachine, NEW_STATE ) );
If you use C++11 you can replace boost::bind with std::bind and boost::function with std::function.
Tha library has a design bug.
The problem is that a function pointer is just a function pointer in C++ (not a closure) and therefore it doesn't have any context.
If you want to create a button that draws a blue circle you will need a global function that will draw a blue circle taking no parameters.
If you want another button to draw a yellow circle you will need another global function that draws a yellow circle taking no parameters.
More specifically the problem is that the library doesn't have any way to store in the button what is called a "context" to be able to pass your code a color to use to draw the circle.
C++11 has added something that reminds a bit closures (not the real thing because of lifetime issues that are hard to solve in any language without garbage collection) but they are not bare function pointers.
What you want to do is just impossible without changing the Button class unless you use some bad hack as the one you can see here that tries to emulate std::bind in C using bare function pointers.
Present is a class to register functions as callbacks.
class Action {
private:
static std::multimap<std::string, std::function<void()>> actions;
public:
static void registerAction(const std::string &key, std::function<void()> action);
}
Obviously it can not register member functions, as function pointer objects to member functions require the class to be specified, but every class should be able to register their functions. std::function<void(Class&)>
Using a template system, I couldn't access all actions from one "instance" of the static class I suppose. How could this be realized?
Example how it should look like:
class B {
public:
B() {
Action::registerAction("some_action", &callMe);
}
void callMe(){}
}
Given that member functions taken an additional argument, you need to bind this argument. For example, you could use something like this:
Action::registerAction("come_action", std::bind(&callMe, this));
The bind() expression will created a function object taking no arguments. Obviously, for this approach to work, this needs to stick around long enough.
you could use std::bind or a lambda function
// std::bind
Action::registerAction( "bla", std::bind(&callMe, this) );
// lambda
Action::registerAction( "bla", [this]() { this->callMe(); } );
i would suggest reading up on lambda functions. Pretty easy to use, and much more powerful than std::bind.
I'm working on a library that's based upon a simple event-system.
For work with GUI elements ("controls"), these are needed a lot. For example, the Window class has got a bunch of events, like "onMouseMove", "onKeyPress", "onKeyRelease", .. However, the basic class for controls is the Control class. It has a virtual function draw (which obviously draws the control) and a virtual function connect which connects the control's and the main window's events (works similar to the Qt Signal-Slot-Concept).
But since the Event class takes an std::function<...> pointer as subject (=> Slot), I cannot simply connect a member function of a derived control class with an event of the window. As a workaround, I'm doing the following thing:
class A : public Control {
friend class Window;
public:
A(){
this->eventHandler = [this] () -> void {
if ( someCondition ) this->onSomeCondition.notify();
};
}
Event<> onSomeCondition;
protected:
std::function<void()> eventHandler;
void connect(Window *window){
window->onSomeHigherEvent.attach(&this->eventHandler);
}
void draw(...) const{
drawSome(...);
}
};
What this basically does is that it assigns a lambda function to the std::function<...> in the constructor and attaches that std::function<...> to the chosen event.
There is a major problem though: What happens if I instantiate a few more objects of that class? If I had the event handlers specified in the class, as a normal function like so:
void eventHandler() {
if ( someCondition ) this->onSomeCondition.notify();
}
And could assign that function to the std::function<...> using std::bind, which does not work for some reason, at least as long as I'm using the following call:
std::bind(&A::eventHandler, this, std::placeholders::_1); // *this will not work since that's just a (reference to the?) copy to of the object.
Anyways, the lambda-function-workaround seems to be less time efficient since it's not really built into the class. Is there a more efficient way to solve this problem? Maybe not by solving the lambda-function problem in particular but by changing the concept?
I'm not sure what your asking, since I can't find the question, but ...
std::bind(&A::eventHandler, this, std::placeholders::_1); // *this will not work since that's just a (reference to the?) copy to of the object.
This creates a callable object that has one unbound parameter, i.e. it expects to be called with one argument, which is not compatible with std::function<void()> because that is a function that expects to be called with no arguments. It's also not compatible with the eventHandler member function you show, because that too takes no arguments.
Maybe you just want to use std::bind(&A::eventHandler, this);
Hey i'm trying to make a very simple GUI using SFML, and i want to be able to attach a function to my Button class in the constructor, as so the user can define what happens when the button is pressed.
I've worked a little before with GLUT and noticed these declerations:
glutReshapeFunc(Resize);
glutDisplayFunc(Draw);
Which apparently define what function should be called when the window is resized or displayed. I want something exactly like this for my button so upon construction you can define what function should be called. I want to be able to pass a function name just like glut, not having define a new class wich overides a virtual functin.
I also doubt it's possible however to pass parameters for these
called functions, as you never know what or how many there would be.
Am i right?
So anyway..... How do i accomplish this or something like it?? Thanks!
You can store a callback using e.g. std::function (for C++0x; boost::function is also available and has a similar interface).
#include <functional>
class Button {
public:
template<typename T>
explicit
Button(T const& t): callback(t) {}
void
press()
{
callback();
}
private:
std::function<void()> callback;
};
// example use with a lambda
Button b([] { do_stuff(); });
b.press(); // will call do_stuff
In C++ it's better to use virtual function approach to address such kind of problems. That's more maintainable at long run.
You can choose to redesign a little bit to your code, where you can have a common handle to various subclasses. Now based on subclass chosen you can call a particular function. For example:
class Shape
{
public:
virtual void Resize () = 0;
virtual void Draw () = 0;
};
class Triangle : public Shape
{
public:
// implement above to functions
};
class Square : public Shape
{
public:
// implement above to functions
};
Now, just pass the handle of Shape* wherever you want and call the above abstract methods;
void foo(Shape *p)
{
p->Resize();
}
(Rewrote everything), I had misread the question.
You seem to be wanting to pass plain old function pointers around to other functions. All you need to do is just pass the name of the function you want, but do so inside an if (or something like that) so the function passed is actualy what you want:
if(i am feeling lucky today){
glutDisplayFunc(DrawMyLuckyShape);
}else{
glutDisplayFunc(DrawAFoo);
}
The bad news is that since C is a nasty language you can't set up to pass extra parameters to your functions (ie, use closures). Therefore, you need to rely on a) the functions being passed some parameter quen being called or b) the functions looking at some global state.