事件模型是被广泛使用的好东西,但是C++标准库里没有现成的,其他实现又复杂或者不优雅,比如需要使用宏。现在VC11可以用在XP下了,那么痛快的拿起C++11提供的先进设施组合出一个轻便的实现吧。

  为了达到简洁的目的,需要放弃一些特性:

  1、不支持判断函数是否已经绑定过(因为std::function不提供比较方法,自己实现function的话代码又变多了)

  2、需要使用者接收返回的回调函数标识来移除事件绑定(原因同上)

  3、事件没有返回值,不支持回调函数优先级、条件回调等事件高级特性(比如返回所有处理结果中的大小值;只回调与指定参数匹配的事件处理函数)

  4、事件参数理论上无限,实际上有限,一般支持0~10个参数(VC11还没有支持变长模板参数,GCC有了。不过可以通过缺省模板参数和偏特化来模拟,所以理论上无限制)

  5、不是线程安全的

  注:3、5两条可以通过引入策略模式来提供灵活支持,像标准库和Loki做的那样,实现一个完整的事件机制。

  简单的实现

#include <map>
 #include <functional>
 
 using namespace std;
 
 
 template<class Param1, class Param2>
 class Event
 {
     typedef void HandlerT(Param1, Param2);
     int m_handlerId;
 
 public:
     Event() : m_handlerId(0) {}
 
     template<class FuncT> int addHandler(FuncT func)
     {
         m_handlers.emplace(m_handlerId, forward<FuncT>(func));
         return m_handlerId++;
     }
 
     void removeHandler(int handlerId)
     {
         m_handlers.erase(handlerId);
     }
 
     void operator ()(Param1 arg1, Param2 arg2)
     {
         for ( const auto& i : m_handlers )
             i.second(arg1, arg2);
     }
 
 private:
     map<int, function<HandlerT>> m_handlers;
 };

  addHandler把回调函数完美转发给std::function,让标准库来搞定各种重载,然后返回一个标识符用来注销绑定。试一下,工作的不错:

void f1(int, int)
 {
     puts("f1()");
 }
 
 struct F2
 {
     void f(int, int)
     {
         puts("f2()");
     }
 
     void operator ()(int, int)
     {
         puts("f3()");
     }
 };
 
 int _tmain(int argc, _TCHAR* argv[])
 {
     Event<int, int> e;
 
     int id = e.addHandler(f1);
 
     e.removeHandler(id);
 
     using namespace std::placeholders;
 
     F2 f2;
 
     e.addHandler(bind(&F2::f, f2, _1, _2));
     e.addHandler(bind(f2, _1, _2));
 
     e.addHandler([](int, int) {
         puts("f4()");
     });
 
     e(1, 2);
 
     return 0;
 }