我正在为游戏引擎创建一个消息传递系统,其中引擎的最终用户可以创建一个消息对象并将其传递给游戏对象,以便由包含附加到游戏对象的组件的侦听器对象进行解释。如果消息与侦听器正在侦听的消息匹配,则侦听器应调用函数指针并将其传递给已接收的消息。基本结构看起来像这样:
class Message
{
std::string message;
};
class Listener
{
std::string target;
void (*fn)(Message*);
};
使用游戏对象的代码来接收类似这样的消息:
//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);
}
}
}
我遇到的问题是,由于上面的代码片段需要调用的函数是组件类型的成员函数,因此我无法将Listener.fn
设置为等于Component::foo
或其他任何其他函数就此而言。
我问我的同学,看看他们是否可以提供任何建议,我收到的两条建议是使用lambdas或使用std::function
将成员函数指针转换为常规函数指针。
我以前从未使用过lambda函数,但在研究here之后,如果我正确地把握它,似乎每次传递消息时我都必须写一个新的lambda使用这样的系统的目的。在研究std::function
here,here和here之后,似乎std::function
会给我提供我需要的灵活性,但实施却给了我很大的帮助错误数量
我是否忽略了lambdas的力量,我是否应该在这种情况下使用std::function
,如果是这样,如何创建一个返回void并获取消息指针的文件?
答案 0 :(得分:5)
std::function
是正确的存储解决方案。 std::function
几乎存储了与其签名兼容的任何内容。
通常你会用lambda填充它。因为这比bind
或其他替代方案更容易,更清晰。
std::function<void(Message*)> fn;
fn = [comp](Message * m){ comp->foo(m); };
答案 1 :(得分:0)
根据我的经历,忘掉古典&#39;函数指针,如果你有权访问C ++ 11。在C ++中编写指向成员函数的指针很复杂。语法不直观,可能会导致脱发:/
正如Yakk所说,std::function
几乎可以在任何情况下发挥作用。 Lambda表达式虽然语法上很笨拙(lambda capture),但非常有用。将它们与std::function
结合使用,你可以实现你想要的任何东西x)
如果你仍然想使用经典函数指针,我建议你阅读这个帖子(这个网站一般用于围绕C ++的其他目的):
https://isocpp.org/wiki/faq/pointers-to-members#fnptr-vs-memfnptr-types