C++ 消息传递系统:回调可以是任何东西

C++ 消息传递系统:回调可以是任何东西,c++,event-handling,boost-bind,C++,Event Handling,Boost Bind,我正在尝试为我的游戏编写一个事件系统。我的事件管理器将存储的回调既可以是普通函数,也可以是函子。我还需要能够比较函数/functor,以便知道需要断开哪个函数/functor与事件管理器的连接 •最初我尝试使用boost::function;它可以很好地处理函数和函子,只是它没有运算符==,所以如果需要的话,我不能删除回调 class EventManager { typedef boost::function<void (boost::weak_ptr<Event>)

我正在尝试为我的游戏编写一个事件系统。我的事件管理器将存储的回调既可以是普通函数,也可以是函子。我还需要能够比较函数/functor,以便知道需要断开哪个函数/functor与事件管理器的连接

•最初我尝试使用boost::function;它可以很好地处理函数和函子,只是它没有运算符==,所以如果需要的话,我不能删除回调

class EventManager
{
    typedef boost::function<void (boost::weak_ptr<Event>)> Callback;
    std::map<Event::Type, std::vector<Callback>> eventHandlerMap_;
};
类事件管理器
{
typedef boost::函数回调;
std::map eventHandlerMap;
};
•我还尝试使用boost::signal,但这也给了我一个与运算符==相关的编译问题:

二进制“==”:未找到接受“常量函子”类型的左侧操作数的运算符(或没有可接受的转换)

无效测试(int c){

std::cout您会发现大多数通用函数包装器不支持函数相等

这是为什么?好吧,看看你的函子:

struct Functor
{
    void operator()(int g) {
        std::cout << "Functor::operator(" << g << ")";
    }
};

有了这个,
HelloWorld
不需要一个
操作符==
,因为你直接指的是信号注册。

你有没有试过libsigc和libsigc++?我开始在linux中使用它们,并爱上了它们。我现在也在Windows应用程序中使用它们。我相信它更具扩展性和灵活性一个Boost。这也是一个很好的实现。

< P>我强烈推荐你考虑Don Clugston的“成员函数指针和最快的C++代表”。你可以找到文章并从这里下载代码:


在许多其他好处中,他的代表提供了比较运算符(=,!=,,不管怎样,我找到了解决方案。一点模板魔术,事情就变得简单了(r):

模板
void EventManager::removeventhandler(事件::类型evType,F func)
{
自动比较=[func](常量回调和其他)->bool{
F const*F=other.target();
如果(f==nullptr)返回false;
返回*f==func;
};
std::vector和回调=。。。;
auto pend=std::remove_if(callbacks.begin()、callbacks.end()、compare);
erase(pend,callbacks.end());
}
模板
void事件管理器::removeEventHandler(
事件::类型evType,常量boost::_bi::bind_t&func)
{
自动比较=[&func](常量回调和其他)->bool{
auto const*f=other.target();
如果(f==nullptr)返回false;
返回函数比较(*f);
};
std::vector和回调=。。。;
auto pend=std::remove_if(callbacks.begin()、callbacks.end()、compare);
erase(pend,callbacks.end());
}
我需要单独处理Boost.Bind对象,因为
操作符==
实际上并没有对绑定对象进行比较,而是生成一个新的functor来比较其他两个()的结果。要比较Boost.Bind,必须使用成员函数
compare()

类型
boost::\u bi::bind\u t
似乎是boost的一种内部类型(我猜这就是名称空间“\u bi”中下划线的意思),但是使用它应该是安全的,因为
boost::function\u equal
的所有重载也使用此类型()


只要定义了执行比较的
运算符==
,或者您使用的是Boost.Bind,此代码将适用于所有类型的函子。我对
std::Bind
(C++0x)进行了初步的研究,但这似乎不具有可比性,因此它与我上面发布的代码不起作用。

@bdonlan信号示例中的一个来自。sorta dup:如果我要保存连接对象,我最好使用vector,而不是保存迭代器,因为函数比信号快。难道没有办法让boost::function com而不是削减内存地址?
boost::function
也会按值捕获,因此地址永远不会相同。我怀疑信号不会比函数的常规向量差太多。
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();
};
struct Functor
{
    void operator()(int g) {
        std::cout << "Functor::operator(" << g << ")";
    }
};
boost::signals::connection c = sig.connect(HelloWorld());
if (c.connected()) {
// c is still connected to the signal
  sig(); // Prints "Hello, World!"
}

c.disconnect(); // Disconnect the HelloWorld object
assert(!c.connected()); c isn't connected any more

sig(); // Does nothing: there are no connected slots
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());
}