4

I am creating a messaging system for a game engine, where in an end user of the engine can create a message object and pass it to a game object to be interpreted by listener objects contained components attached to the game object. if the message matches a message that the listener is listening for, then the listener should call a function pointer and pass it the message that was received. The basic structure looking something like this:

class Message
{
    std::string message;
};

class Listener
{
    std::string target;
    void (*fn)(Message*);
};

with the game object's code to receive a message looking something like this:

//if the queue is empty then dont do anything
if (messageQueue.empty())
{
    return;
}

//else grab the front of the queue
Message* newMessage = messageQueue.front();

//pop our message from the queue
messageQueue.pop();

//for each component in our list
for (std::vector<Component*>::iterator i = ComponentList.begin(); i < ComponentList.end(); i++)
{
    Component* itemp = *i;
    //for each message in its listener list
    for (std::vector<Listener*>::iterator j = itemp->Listeners.begin(); j < itemp->Listeners.end(); j++)
    {
        Listener* jtemp = *j;
        //check the listener against the newMessage
        if (jtemp->name == newMessage->name)
        {
            //call jtemp's function
            jtemp->function(newMessage);
        }
    }
}

the issue that I have ran into is that since the functions that need to be called by the snippet above are member functions of a component type, I cannot set Listener.fn to equal Component::foo or any other function for that matter.

I asked around my classmates to see if they could offer any advice and the two pieces of advice I received were either use lambdas or use std::function to convert a member function pointer into a regular function pointer.

I've never used a lambda function before, but after researching here, if I'm grasping it correctly, it seems like I would have to write a new lambda each time I pass a message which defeats the purpose of using a system like this. And after researching std::function here, here, and here it seems like std::function would give me the flexibility that I need but implementation has been giving me a large number of errors

Am I overlooking the power of lambdas, should I be using a std::function in this case, and if so how can a create one that returns void and takes a message pointer?

Community
  • 1
  • 1
Potat
  • 43
  • 1
  • 4
  • You seem to have found all the resources you need to answer your own question. I would suggest you try to use them and if you still cannot solve your problem, come back to us with a specific question about the error you're getting. – Barry Sep 10 '16 at 17:23
  • It is not possible to convert member function pointer into an ordinary function pointer regardless of what you use. C++ does not offer any standard features for such conversion. Neither `std::function` nor lambdas can help you to achieve that. You can switch to using `std::function` *instead* of function pointer, but that means that you will have to forget about "ordinary function pointer" for good. – AnT stands with Russia Sep 10 '16 at 18:45
  • 1
    omg. Please use range-based for loops – jterm Apr 19 '18 at 15:23

2 Answers2

6

std::function is the right solution for storage. std::function stores almost anything that is compatible with its signature.

Usually you will populate it with a lambda. Because that is easier and clearer than bind or other alternatives.

std::function<void(Message*)> fn;

fn = [comp](Message * m){ comp->foo(m); };
Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524
0

From what I experienced, forget about 'classical' function pointers if you have access to C++11. Writing pointer to member functions in C++ is, well... complicated. The syntax is not intuitive, and can lead to hair loss :/

As Yakk stated, std::function will work in almost any situation. Lambda expressions are, although syntactically akward and subtle (lambda capture), quite useful. Combine them with std::function and you could probably achieve whatever you want x)

If you still want to use classical function pointer, I recommend you read this thread (and this website in general for other purposes revolving around C++):
https://isocpp.org/wiki/faq/pointers-to-members#fnptr-vs-memfnptr-types

Naliwe
  • 322
  • 1
  • 8