消息系统:回调可以是任何东西
我正在尝试为我的游戏编写一个事件系统。我的事件管理器将存储的回调可以是普通函数也可以是函子。我还需要能够比较函数/函子,以便我知道需要从事件管理器断开哪一个。
• 最初我尝试使用boost::function;它可以很好地处理函数和函子,只是它没有运算符==,所以如果我想的话,我无法删除回调。
class EventManager
{
typedef boost::function<void (boost::weak_ptr<Event>)> Callback;
std::map<Event::Type, std::vector<Callback>> eventHandlerMap_;
};
• 我也尝试过使用boost::signal,但这也给我带来了与operator==相关的编译问题:
二进制“==”:找不到采用“const Functor”类型的左侧操作数的运算符(或者没有可接受的转换)
void test(int c) {
std::cout << "test(" << c << ")";
}
struct Functor
{
void operator()(int g) {
std::cout << "Functor::operator(" << g << ")";
}
};
int main()
{
boost::signal<void (int)> sig;
Functor f;
sig.connect(test);
sig.connect(f);
sig(7);
sig.disconnect(f); // Error
}
关于如何实现此操作的任何其他建议?或者也许我如何才能使 boost:: function 或 boost::signal 工作? (不过,我宁愿使用 boost:: 函数,因为我听说对于小型项目集合来说信号相当慢。)
编辑: 这是我希望 EventManager 具有的界面。
class EventManager
{
public:
void addEventHandler(Event::Type evType, Callback func);
void removeEventHandler(Event::Type evType, Callback func);
void queueEvent(boost::shared_ptr<Event> ev);
void dispatchNextEvent();
};
I'm trying to write an event system for my game. The callbacks that my event manager will store can be both plain functions as well as functors. I also need to be able to compare functions/functors so I know which one I need to disconnect from the event manager.
• Initially I tried using boost::function; it handles functions and functors perfectly well, except it has no operator==, so I can't remove callbacks if I want to.
class EventManager
{
typedef boost::function<void (boost::weak_ptr<Event>)> Callback;
std::map<Event::Type, std::vector<Callback>> eventHandlerMap_;
};
• I also tried using boost::signal, but that also gives me a compilation problem related to operator==:
binary '==' : no operator found which takes a left-hand operand of type 'const Functor' (or there is no acceptable conversion)
void test(int c) {
std::cout << "test(" << c << ")";
}
struct Functor
{
void operator()(int g) {
std::cout << "Functor::operator(" << g << ")";
}
};
int main()
{
boost::signal<void (int)> sig;
Functor f;
sig.connect(test);
sig.connect(f);
sig(7);
sig.disconnect(f); // Error
}
Any other suggestions about how I might implement this? Or maybe how I can make either boost:: function or boost::signal work? (I'd rather use boost:: function though, since I've heard signal is rather slow for small collections of items.)
Edit: This is the interface of that I'd like EventManager to have.
class EventManager
{
public:
void addEventHandler(Event::Type evType, Callback func);
void removeEventHandler(Event::Type evType, Callback func);
void queueEvent(boost::shared_ptr<Event> ev);
void dispatchNextEvent();
};
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
您会发现大多数通用函数包装器不支持函数相等。
这是为什么呢?好吧,只要看看你的函子:
这个函子没有运算符==,因此无法比较相等性。因此,当您将其传递给
boost::signal
按值时,会创建一个新实例;这将比较指针相等性为 false,并且没有运算符来测试值相等性。事实上,大多数函子没有值相等谓词。它没有多大用处。处理这个问题的通常方法是使用回调句柄; boost::signals 通过其
connection
对象来完成此操作。例如,请查看 文档:有了这个,
HelloWorld
不需要有operator==
,因为您直接引用信号注册。You'll find that most generic function wrappers do not support function equality.
Why is this? Well, just look at your functor there:
This
Functor
has nooperator==
, and therefore cannot be compared for equality. So when you pass it toboost::signal
by value, a new instance is created; this will compare false for pointer-equality, and has no operator to test for value-equality.Most functors don't, in fact, have value-equality predicates. It's not useful very much. The usual way to deal with this is to have a handle to the callback instead; boost::signals does this with its
connection
object. For example, take a look at this example from the documentation:With this,
HelloWorld
doesn't need to have anoperator==
, as you're referring directly to the signal registration.您尝试过 libsigc 和 libsigc++ 吗?我开始在 Linux 中使用它们并爱上了它们。我现在也在我的 Windows 应用程序中使用它们。我相信它比 boost 更具可扩展性和灵活性。实施起来也轻而易举。
Have you ever tried libsigc and libsigc++? I started using them in linux and fell in love with them. I now use them in my Windows applications as well. I believe it is more extensible and flexible than boost. It is also a breeze to implement.
我强烈建议您考虑 Don Clugston 的“成员函数指针和最快的 C++ 委托”。您可以从此处找到该文章并下载代码:
http://www.codeproject.com /KB/cpp/FastDelegate.aspx
在许多其他好处中,他的委托提供了开箱即用的比较运算符(==、!=、<)。我目前正在将它们用于实时系统,并发现它们在各方面都非常出色。我似乎记得我们必须进行一些小的修改才能解决编译器的可移植性问题;但是,这种体验会根据平台等的不同而有所不同。
此外,这篇文章已经有好几年了,所以如果您遇到任何问题,您可能需要通过谷歌搜索有关此委托实现的更新代码/讨论。
I highly recommend you consider Don Clugston's "Member Function Pointers and the Fastest Possible C++ Delegates". You can find the article and download the code from here:
http://www.codeproject.com/KB/cpp/FastDelegate.aspx
Among many other benefits, his delegates provide comparison operators (==, !=, <) out of the box. I'm currently using them for a realtime system and find them excellent in every way. I do seem to recall we had to make a minor modification to fix a compiler portability issue; but, that experience will vary based on platform etc.
Also, the article is several years old so you may want to google around for updated code/discussion regarding this delegate implementation if you run into any problems.
没关系,我找到了解决方案。一点模板魔法,事情就变得简单了(r):
我需要单独处理 Boost.Bind 对象,因为
operator==
实际上并不对 Bind 对象进行比较,而是生成一个新的函子来比较其他两个的结果(了解更多) 。要比较 Boost.Bind,您必须使用成员函数compare()
。类型
boost::_bi::bind_t
似乎是 Boost 的内部类型(我猜这就是命名空间“_bi”中下划线的含义),但是将它用作所有重载应该是安全的boost::function_equal
也使用这种类型(参考)。只要定义了一个进行比较的
operator==
,或者您使用的是 Boost.Bind,此代码就适用于所有类型的函子。我粗略地了解了std::bind
(C++0x),但这似乎没有可比性,因此它不适用于我上面发布的代码。No matter, I found the solution. A little template magic and things become simple(r):
I need to handle Boost.Bind objects separately because
operator==
doesn't actually do comparison for Bind objects, but produce a new functor that compares the result of the other two (read more). To compare Boost.Bind you have to use the member functioncompare()
.The type
boost::_bi::bind_t
seems to be an internal type of Boost (I guess that's what the underscore in namespace '_bi' means), however it should be safe to use it as all overloads ofboost::function_equal
also use this type (reference).This code will work for all types of functors as long as there is an
operator==
defined that does comparison, or if you're using Boost.Bind. I had a superficial look intostd::bind
(C++0x), but that doesn't seem to be comparable, so it won't work with the code I posted above.