How can I pass a pointer to member function (polymorphic structure)?

I am trying to create a callback system for input events in my game engine.

Here is a cut down version of the EventManager.h file

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include "Controls.h"
#include "Object.h"

enum MouseEventType{PRESSED, POINTER_AT_POSITION, PRESSED_AT_POSITION };

struct KeyEvent{
	sf::Keyboard::Key key;
	KeyState keyState;
};

struct MouseEvent{
	sf::Mouse::Button button;
	KeyState buttonState;
	sf::Vector2f position;
	MouseEventType type;
};

class InputEvent{
public:
	std::vector<KeyEvent> keyEvents;
	std::vector<MouseEvent> mouseEvents;
};

class CallbackEvent{
private:
	Controls* controls;
	InputEvent event;
	void (*functionToCall)(void);

public:
	CallbackEvent(Controls* controls, InputEvent event, void (*functionToCall)(void));
	void checkEvent();
};

class EventManager{
private:
	Controls* controls;
	std::vector<CallbackEvent> callbackEvents;

public:
	EventManager(Controls* controls);
	void watchEvent(InputEvent event, void(*functionToCall)(void));

	void checkEvents();
};


This works if the function pointer being passed to the event manager is not a member function.

I have two other classes Scene and Object that could potentially use this EventManager to create callback events. Scene and Object are both pure virtual objects. How can I pass a pointer to a member function of the child classes of both Scene and Object? I am fine with just having two separate watchEvent functions for Scene and Object but how do I pass the type of the Object or the type of the Scene? The child classes are unknown as they are being created by someone using this game engine.

For example, if I want to make a player object it would be something like

class PlayerObject : public Object{...};

Now that PlayerObject type has to find its way to PlayerObject::functionToCall(). I think I need templates to do this but, since I never used them before, I have no clue if I am using them correctly or not to do this.

This is how I intend to use this

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class OtherScene : public Scene{
        void p_pressed(void){
                //pause
        }

        void onStart(){
                InputEvent event;
	        KeyEvent keyEvent;
	        keyEvent.key = sf::Keyboard::P;
	        keyEvent.keyState = KEY_PRESSED;
	        event.keyEvents.push_back(keyEvent);
	        eventManager->watchEvent(event, &OtherScene::p_pressed);
        }
};


Any help is appreciated.
Last edited on
I'm just explaining the syntax here:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class EventManager {
    void foo(InputEvent event, void(EventManager::*functionToCall)(void)) {
        // ...
        (this->*functionToCall)();
        // ....
    }

    void bar(InputEvent event, double(CallbackEvent::*f)(int, char) const) {
        // ...
        const CallbackEventObject c;
        double d = (c.*f)(3, 'k');  // Note that f is const.
        // ....
    }
    public:
       void function() {}
};

class CallbackEvent {
    public:
       double baz (int a, char b) const { // ...}
};

int main() {
    EventManager e;
    InputEvent in;
    e.foo(in, &EventManager::function);
    e.bar(in, &CallbackEvent::baz);
};


Note that you must specify the object to use the function pointer, else dereferencing it and calling up its parameters will have no meaning. If the function is const, then you must place the const keyword at the end of parameter too.
If the function pointer is that of a static member function, then your original syntax will work, because there is no object to use. You might want to read up on std::bind as well.
Last edited on
Is there anyway to specify the type without knowing it until run time?

Until I figure this out I guess I can make them static member functions. I have one question though which might be stupid. If I have multiple instances of PlayerObject and it has a static member function p_pressed(), how does the computer know which PlayerObject to operate on when that function is dereferenced and called.
Last edited on
Forward http://en.cppreference.com/w/cpp/utility/forward
bind http://en.cppreference.com/w/cpp/utility/functional/bind
and wrap http://en.cppreference.com/w/cpp/utility/functional/function

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include <iostream>
#include <functional>
#include <utility>
#include <vector>

struct A
{
    using callback_type = std::function< void() > ;

    template < typename FN, typename... ARGS > void register_callback( FN&& fn, ARGS&&... args )
    { callbacks.emplace_back( std::bind( std::forward<FN>(fn), std::forward<ARGS>(args)... ) ) ; }

    void do_callback() const { for( auto& fn : callbacks ) fn() ; }

    std::vector<callback_type> callbacks ;
};

int foo( int a, int b ) { std::cout << "::foo(" << a << ',' << b << ")\n" ; return a+b ; }

struct bar { void operator() ( double& d ) const { std::cout << "bar::operator()(" << d << ")\n" ; d += 1 ; } };

int main()
{
    const auto closure = []( int a, double d ) { std::cout << "main::closure(" << a << ',' << d << ")\n" ; return a+d ; };

    struct B { int v = 7 ; void mem_fun( int x ) { std::cout << "B::memfun(" << this << ',' << x << ")\n" ; v *= 9 ; } };

    A a ;
    B b ;
    double d = 9.9 ;
    a.register_callback( foo, 12, 34 ) ;
    a.register_callback( bar(), std::ref(d) ) ;
    a.register_callback( closure, 12, 3.4 ) ;
    a.register_callback( &B::mem_fun, std::ref(b), 56 ) ;

    a.do_callback() ;
    
    std::cout << d << ' ' << b.v << '\n' ;
}

http://coliru.stacked-crooked.com/a/9daf354aa6c42855
Ok, I am trying to get that working with my EventManager but I am getting an error that I am not sure how to fix (it doesn't help that I don't understand the error).

error C2664: 'void std::_Func_class<_Ret,>::_Set(std::_Func_base<_Ret,> *)' : cannot convert argument 1 from '_Myimpl *' to 'std::_Func_base<_Ret,> *


Here is what I have so far. I might be doing something wrong with the templates as I have never used them before.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//chopped up EventManager.h
#include <functional>
class CallbackEvent{
private:
	std::function<void()> functionToCall;

public:
	template<class TYPE>
	CallbackEvent(TYPE&& fn){
		this->functionToCall = std::forward<TYPE>(fn);
	}
};

class EventManager{
private:
	std::vector<CallbackEvent> callbackEvents;

public:	
	template<class TYPE>
	void watchEvent(TYPE&& fn){
		CallbackEvent callbackEvent(fn);
		callbackEvents.push_back(callbackEvent);
	}
};


And this is how I am using it

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//Test.h
#ifndef TEST
#define TEST

#include "EventManager.h"

class Test{
public:
	EventManager eventManager;

	void test_callee(void){
		//do stuff
	}

	void test_callback_creator(){
		eventManager.watchEvent(&Test::test_callee);
	}

};

#endif 


I shouldn't need std::bind for anything because I don't intend for there to be any arguments. At least for now.
> I shouldn't need std::bind for anything because I don't intend for there to be any arguments.

Test::test_callee is a non-static member function; an object of type Test is an implicit argument (which can be accessed through the this pointer). We need to bind that argument.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#include <iostream>
#include <functional>
#include <vector>

//chopped up EventManager.h
#include <functional>
class CallbackEvent{
private:
    std::function<void()> functionToCall;

public:
    CallbackEvent( std::function<void()> fn ) : functionToCall(fn) {}

    /*
    template<class TYPE>
	CallbackEvent(TYPE&& fn){
		this->functionToCall = std::forward<TYPE>(fn);
	}
	*/

};

class EventManager{
private:
	std::vector<CallbackEvent> callbackEvents;

public:
	template<class TYPE>
	void watchEvent(TYPE&& fn){
		// CallbackEvent callbackEvent(fn);
		// callbackEvents.push_back(callbackEvent);
		callbackEvents.emplace_back( std::forward<TYPE>(fn) ) ;
	}
};

class Test{
public:
	EventManager eventManager;

	void test_callee(void){
		//do stuff
	}

	void test_callback_creator(){
		// eventManager.watchEvent(&Test::test_callee);
		eventManager.watchEvent( std::bind( &Test::test_callee, this ) );
	}

};

int main()
{
}

http://coliru.stacked-crooked.com/a/6eea3a1895cc26fa
Ohh ok. I almost had it correct, I just underestimated what std::bind did. I should have read through it some more. Thanks!
Topic archived. No new replies allowed.