消息系统:回调可以是任何东西 [英] Messaging system: Callbacks can be anything

查看:161
本文介绍了消息系统:回调可以是任何东西的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想为我的游戏写一个事件系统。我的事件管理器将存储的回调可以是普通函数以及函子。我还需要能够比较函数/函子,所以我知道哪一个我需要断开与事件管理器。

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.

•最初我尝试使用boost :: function;它完美地处理函数和函数,除非它没有操作符==,所以如果我想,我不能删除回调。

• 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_;
};

•我也尝试使用boost :: signal,但这也给我一个编译问题==:

• I also tried using boost::signal, but that also gives me a compilation problem related to operator==:


binary'==':无操作符,它接受类型为const Functor的左手操作数是不可接受的转换)

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
}

有关如何实现这一点的任何其他建议?或者也许我可以使boost :: function或boost :: signal工作? (我宁愿使用boost :: function虽然,因为我听说信号对于小集合的项目是相当缓慢。)

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:这是我想要的EventManager的接口。

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();
};


推荐答案

一个小的模板魔法和事情变得简单(r):

No matter, I found the solution. A little template magic and things become simple(r):

template<typename F>
void EventManager::removeEventHandler(Event::Type evType, F func)
{
    auto compare = [func](const Callback& other) -> bool {
        F const* f = other.target<F>();
        if (f == nullptr) return false;
        return *f == func;
    };

    std::vector<Callback>& callbacks = ...;
    auto pend = std::remove_if(callbacks.begin(), callbacks.end(), compare);
    callbacks.erase(pend, callbacks.end());
}


template<typename R, typename F, typename L>
void EventManager::removeEventHandler(
    Event::Type evType, const boost::_bi::bind_t<R, F, L>& func)
{
    auto compare = [&func](const Callback& other) -> bool {
        auto const* f = other.target<boost::_bi::bind_t<R, F, L>>();
        if (f == nullptr) return false;
        return func.compare(*f);
    };

    std::vector<Callback>& callbacks = ...;
    auto pend = std::remove_if(callbacks.begin(), callbacks.end(), compare);
    callbacks.erase(pend, callbacks.end());
}



我需要单独处理Boost.Bind对象,因为 operator == 实际上不会对Bind对象进行比较,但会产生一个新的函子,比较其他两个函数的结果(了解详情)。要比较Boost.Bind,必须使用成员函数 compare()

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 function compare().

类型 boost :: _ bi :: bind_t 似乎是一个内部类型的Boost(我猜这是命名空间'_bi'中的下划线意味着),但它应该是安全的使用它作为所有重载 boost :: function_equal 也使用此类型(参考)。

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 of boost::function_equal also use this type (reference).

此代码将适用于所有类型的函子,只要有 operator == 定义比较,或者如果您使用Boost.Bind。我有一个表面看看 std :: bind (C + + 0x),但是似乎不可比较,所以它不会与代码一起工作贴上。

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 into std::bind (C++0x), but that doesn't seem to be comparable, so it won't work with the code I posted above.

这篇关于消息系统:回调可以是任何东西的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆