How to handle callback functions?

I'm trying to register functions for getting called back by an event handler, but I don't know how to pass methods of object which holds the callees to the event handler. I want to make the type which holds the callee independent, so that it could be a button object or a window e.g.

Below is a truncated example of my program:
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
#include <iostream>
#include <vector>

class Callee
{
public:
    void calledFunction(const std::string& event) { std::cout << event; }
};

class EventHandler
{
public:
    void add( void (*)(const std::string&) );
    void callBack( const std::string& event);
private:
    std::vector<void (*)(const std::string&)> m_callees;
};

void
EventHandler::add( void(*callee)(const std::string&) )
{
    m_callees.push_back( callee );
}

void
EventHandler::callBack( const std::string& event)
{
    for( auto & callee : m_callees)
        callee( event );
}

int main()
{
    Callee callee;    
    EventHandler eventHandler;
    eventHandler.add(callee.calledFunction );
    eventHandler.callBack( "I'm an event.\n");
}

Here thecompiler error message:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
main.cpp: In function 'int main()':

main.cpp:36:44: error: invalid use of non-static member function 'void Callee::calledFunction(const string&)'

     eventHandler.add(callee.calledFunction );

                                            ^

main.cpp:7:10: note: declared here

     void calledFunction(const std::string& event) { std::cout << event; }

          ^~~~~~~~~~~~~~



*edited
Last edited on
Which standard(s) of C++ are you allowed to use?

Are you allowed to use any libraries, like say boost?
I have no restriction, I'm a hobby coder :)
The following version compiles without warnings and seems to work, but function pointers syntax is so weird I’m not asserting that’s correct anyway.

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
#include <iostream>
#include <vector>

class Callee
{
public:
    void calledFunction(const std::string& event) { std::cout << event; }
};

class EventHandler
{
public:
    void add( void (Callee::*calledFunction)(const std::string&) );
    void callBack( const std::string& event);
private:
    std::vector<void (Callee::*)(const std::string&)> m_callees;
    Callee callee;
};

void
EventHandler::add( void(Callee::*calledFunction)(const std::string&) )
{
    m_callees.push_back( calledFunction );
}

void
EventHandler::callBack( const std::string& event)
{
    for(const auto & e : m_callees) {
        (callee.*(e))(event);
    }
}

int main()
{
    Callee callee;
    EventHandler eventHandler;
    eventHandler.add(callee.calledFunction);
    eventHandler.callBack( "I'm an event.\n" );
}


Output:
I'm an event.


Since you want to store a pointer to a member function, it seems you need an instance of that class to invoke it against.
Perhaps things could become easier using std::function or std::invoke() or other facilities from the <functional> header.
I get at your code the error:
 In function 'int main()': 38:56: error: invalid use of non-static member function 


If your code beside this would work, I contemplate deriving from Callee for all classes which would register a method to the event handler. Would this be a current method?
That's weird: I don't get any error on my W7 environment.
Anyway, could you please try this:

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
#include <iostream>
#include <vector>

class Callee
{
public:
    void calledFunction(const std::string& event) { std::cout << event; }
};

class EventHandler
{
public:
    void add( void (Callee::*calledFunction)(const std::string&) );
    void callBack( const std::string& event);
private:
    std::vector<void (Callee::*)(const std::string&)> m_callees;
    Callee callee;
};

void
EventHandler::add( void(Callee::*calledFunction)(const std::string&) )
{
    m_callees.push_back( calledFunction );
}

void
EventHandler::callBack( const std::string& event)
{
    for(const auto & e : m_callees) {
        (callee.*(e))(event);
    }
}

int main()
{
    // Callee callee;
    EventHandler eventHandler;
    eventHandler.add(&Callee::calledFunction);
    eventHandler.callBack( "I'm an event.\n" );
}

Consider wrapping the callback in a call wrapper.
https://en.cppreference.com/w/cpp/utility/functional/function

A simple example:

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
54
#include <iostream>
#include <functional>
#include <utility>
#include <vector>

struct event_handler
{
    using callback_type = std::function< void(const std::string&) > ;

    template < typename FN >
    void register_callback( FN fn )
    { callbacks.emplace_back( fn ) ; }

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

    std::vector<callback_type> callbacks ;
};

int foo( const std::string& event )
{
    std::cout << "::foo(" << event << ")\n" ;
    return 5 ;
}

struct callee
{
    void called_function ( std::string event ) const
    { std::cout << "callee::called_function(" << event << ")\n" ; }
};

int main()
{
    const auto closure = []( const std::string& event )
    { std::cout << "main::closure(" << event << ")\n" ; return "hello" ; };

    event_handler handler ;

    handler.register_callback(foo) ; // registered event handler is a non member function

    // registered event handler is a non-static member function.
    // bind the object on which the function is to be called
    using std::placeholders::_1 ;
    callee called_object ;
    handler.register_callback( std::bind( &callee::called_function, std::ref(called_object), _1 ) ) ;

    handler.register_callback(closure) ; // registered event handler is a closure object

    for( int i = 0 ; i < 3 ; ++i )
    {
        std::cout << "\nevent #" << i << "\n---------------\n" ;
        handler.do_callback( "event #" + std::to_string(i) ) ;
    }
}

http://coliru.stacked-crooked.com/a/328c1b8cba1e0ce9
@Enoizat: Thanks, your example works now.
@JLBorges: Thank you for this great example how using the functional facilities. I will reading up deeper at this topic.
I contemplate deriving from Callee

JLBorges's code looks as if it doesn't need polymorphism...
Topic archived. No new replies allowed.