C++中事件机制的简洁实现

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

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

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

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

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

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

5、不是线程安全的

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

最简单的实现

1 #include <map>
 2 #include <functional>
 3 
 4 using namespace std;
 5 
 6 
 7 template<class Param1, class Param2>
 8 class Event
 9 {
10     typedef void HandlerT(Param1, Param2);
11     int m_handlerId;
12 
13 public:
14     Event() : m_handlerId(0) {}
15 
16     template<class FuncT> int addHandler(FuncT func)
17     {
18         m_handlers.emplace(m_handlerId, forward<FuncT>(func));
19         return m_handlerId++;
20     }
21 
22     void removeHandler(int handlerId)
23     {
24         m_handlers.erase(handlerId);
25     }
26 
27     void operator ()(Param1 arg1, Param2 arg2)
28     {
29         for ( const auto& i : m_handlers )
30             i.second(arg1, arg2);
31     }
32 
33 private:
34     map<int, function<HandlerT>> m_handlers;
35 };

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

1 void f1(int, int)
 2 {
 3     puts("f1()");
 4 }
 5 
 6 struct F2
 7 {
 8     void f(int, int)
 9     {
10         puts("f2()");
11     }
12 
13     void operator ()(int, int)
14     {
15         puts("f3()");
16     }
17 };
18 
19 int _tmain(int argc, _TCHAR* argv[])
20 {
21     Event<int, int> e;
22 
23     int id = e.addHandler(f1);
24 
25     e.removeHandler(id);
26 
27     using namespace std::placeholders;
28 
29     F2 f2;
30 
31     e.addHandler(bind(&F2::f, f2, _1, _2));
32     e.addHandler(bind(f2, _1, _2));
33 
34     e.addHandler([](int, int) {
35         puts("f4()");
36     });
37 
38     e(1, 2);
39 
40     return 0;
41 }

虽然这里有一个小小的缺点,对于仿函数,如果想使用它的指针或引用是不可以直接绑定的,需要这样做:

1 e.addHandler(ref(f2));
2 e.addHandler(ref(*pf2));    // pf2是指向f2的指针

但是使用仿函数对象指针的情形不多,也不差多敲几个字符,何况在有Lambda表达式的情况下呢?

改进

1、有人不喜欢bind,用起来麻烦,放到addhandler里面去:

1         template<class ObjT, class FuncT> int addHandler(ObjT obj, FuncT func)
2         {
3             using namespace std::placeholders;
4             m_handlers.emplace(m_handlerId, std::bind(func, std::forward<ObjT>(obj), _1, _2));
5             return m_handlerId++;
6         }

2、扩展参数个数。没有变长模板参数,变通一下:

1 struct NullType {};
 2 
 3 template<class P1 = Private::NullType, class P2 = Private::NullType>
 4 class Event 
 5 {
 6 public:
 7     template<class ObjT, class FuncT> int addHandler(ObjT obj, FuncT func)
 8     {
 9         using namespace std::placeholders;
10         m_handlers.emplace(m_handlerId, std::bind(func, std::forward<ObjT>(obj), _1, _2));
11         return m_handlerId++;
12     }
13 
14     void operator ()(P1 arg1, P2 arg2)
15     {
16         for ( const auto& i : m_handlers )
17             i.second(arg1, arg2);
18     }
19 };
20 
21 template<>
22 class Event<Private::NullType, Private::NullType>
23 {
24 public:
25     template<class ObjT, class FuncT> int addHandler(ObjT obj, FuncT func)
26     {
27         using namespace std::placeholders;
28         m_handlers.emplace(m_handlerId, std::bind(func, std::forward<ObjT>(obj)));
29         return m_handlerId++;
30     }
31 
32     void operator ()()
33     {
34         for ( const auto& i : m_handlers )
35             i.second();
36     }
37 };
38 
39 template<class P1>
40 class Event<P1, Private::NullType>
41 {
42 public:
43     template<class ObjT, class FuncT> int addHandler(ObjT obj, FuncT func)
44     {
45         using namespace std::placeholders;
46         m_handlers.emplace(m_handlerId, std::bind(func, std::forward<ObjT>(obj), _1));
47         return m_handlerId++;
48     }
49 
50     void operator ()(P1 arg1)
51     {
52         for ( const auto& i : m_handlers )
53             i.second(arg1);
54     }
55 };

现在支持0~2个参数了。注意到各个模板里有公共代码,提取出来放进基类,然后要做的就是打开文本生成器了

补充一下:VC里std::function默认最多5个参数,最多支持10个,要在编译开关里设置一下宏_VARIADIC_MAX=10

完整代码

代码下载
C++中事件机制的简洁实现C++中事件机制的简洁实现View Code

1 #pragma once
  2 
  3 #include <map>
  4 #include <functional>
  5 
  6 
  7 namespace Utility
  8 {
  9     namespace Private
 10     {
 11         struct NullType {};
 12 
 13         template<class HandlerT>
 14         class EventBase
 15         {
 16         public:
 17             EventBase() : m_handlerId(0) {}
 18 
 19             template<class FuncT> int addHandler(FuncT func)
 20             {
 21                 m_handlers.emplace(m_handlerId, std::forward<FuncT>(func));
 22                 return m_handlerId++;
 23             }
 24 
 25             void removeHandler(int handlerId)
 26             {
 27                 m_handlers.erase(handlerId);
 28             }
 29 
 30         protected:
 31             int m_handlerId;
 32             std::map<int, std::function<HandlerT>> m_handlers;
 33         };
 34     }
 35 
 36     template<class P1 = Private::NullType, class P2 = Private::NullType, class P3 = Private::NullType, class P4 = Private::NullType, class P5 = Private::NullType, class P6 = Private::NullType, class P7 = Private::NullType, class P8 = Private::NullType, class P9 = Private::NullType, class P10 = Private::NullType>
 37     class Event 
 38         : public Private::EventBase<void (P1, P2, P3, P4, P5, P6, P7, P8, P9, P10)>
 39     {
 40     public:
 41         using Private::EventBase<void (P1, P2, P3, P4, P5, P6, P7, P8, P9, P10)>::addHandler;
 42 
 43         template<class ObjT, class FuncT> int addHandler(ObjT obj, FuncT func)
 44         {
 45             using namespace std::placeholders;
 46             m_handlers.emplace(m_handlerId, std::bind(func, std::forward<ObjT>(obj), _1, _2, _3, _4, _5, _6, _7, _8, _9, _10));
 47             return m_handlerId++;
 48         }
 49 
 50         void operator ()(P1 arg1, P2 arg2, P3 arg3, P4 arg4, P5 arg5, P6 arg6, P7 arg7, P8 arg8, P9 arg9, P10 arg10)
 51         {
 52             for ( const auto& i : m_handlers )
 53                 i.second(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10);
 54         }
 55     };
 56 
 57     template<>
 58     class Event<Private::NullType, Private::NullType, Private::NullType, Private::NullType, Private::NullType, Private::NullType, Private::NullType, Private::NullType, Private::NullType, Private::NullType>
 59         : public Private::EventBase<void ()>
 60     {
 61     public:
 62         using Private::EventBase<void ()>::addHandler;
 63 
 64         template<class ObjT, class FuncT> int addHandler(ObjT const obj, FuncT func)
 65         {
 66             m_handlers.emplace(m_handlerId, std::bind(func, obj));
 67             return m_handlerId++;
 68         }
 69 
 70         void operator ()()
 71         {
 72             for ( const auto& i : m_handlers )
 73                 i.second();
 74         }
 75     };
 76 
 77     template<class P1>
 78     class Event<P1, Private::NullType, Private::NullType, Private::NullType, Private::NullType, Private::NullType, Private::NullType, Private::NullType, Private::NullType, Private::NullType>
 79         : public Private::EventBase<void (P1)>
 80     {
 81     public:
 82         using Private::EventBase<void (P1)>::addHandler;
 83 
 84         template<class ObjT, class FuncT> int addHandler(ObjT obj, FuncT func)
 85         {
 86             using namespace std::placeholders;
 87             m_handlers.emplace(m_handlerId, std::bind(func, std::forward<ObjT>(obj), _1));
 88             return m_handlerId++;
 89         }
 90 
 91         void operator ()(P1 arg1)
 92         {
 93             for ( const auto& i : m_handlers )
 94                 i.second(arg1);
 95         }
 96     };
 97 
 98     template<class P1, class P2>
 99     class Event<P1, P2, Private::NullType, Private::NullType, Private::NullType, Private::NullType, Private::NullType, Private::NullType, Private::NullType, Private::NullType>
100         : public Private::EventBase<void (P1, P2)>
101     {
102     public:
103         using Private::EventBase<void (P1, P2)>::addHandler;
104 
105         template<class ObjT, class FuncT> int addHandler(ObjT obj, FuncT func)
106         {
107             using namespace std::placeholders;
108             m_handlers.emplace(m_handlerId, std::bind(func, std::forward<ObjT>(obj), _1, _2));
109             return m_handlerId++;
110         }
111 
112         void operator ()(P1 arg1, P2 arg2)
113         {
114             for ( const auto& i : m_handlers )
115                 i.second(arg1, arg2);
116         }
117     };
118 
119     template<class P1, class P2, class P3>
120     class Event<P1, P2, P3, Private::NullType, Private::NullType, Private::NullType, Private::NullType, Private::NullType, Private::NullType, Private::NullType>
121         : public Private::EventBase<void (P1, P2, P3)>
122     {
123     public:
124         using Private::EventBase<void (P1, P2, P3)>::addHandler;
125 
126         template<class ObjT, class FuncT> int addHandler(ObjT obj, FuncT func)
127         {
128             using namespace std::placeholders;
129             m_handlers.emplace(m_handlerId, std::bind(func, std::forward<ObjT>(obj), _1, _2, _3));
130             return m_handlerId++;
131         }
132 
133         void operator ()(P1 arg1, P2 arg2, P3 arg3)
134         {
135             for ( const auto& i : m_handlers )
136                 i.second(arg1, arg2, arg3);
137         }
138     };
139 
140     template<class P1, class P2, class P3, class P4>
141     class Event<P1, P2, P3, P4, Private::NullType, Private::NullType, Private::NullType, Private::NullType, Private::NullType, Private::NullType>
142         : public Private::EventBase<void (P1, P2, P3, P4)>
143     {
144     public:
145         using Private::EventBase<void (P1, P2, P3, P4)>::addHandler;
146 
147         template<class ObjT, class FuncT> int addHandler(ObjT obj, FuncT func)
148         {
149             using namespace std::placeholders;
150             m_handlers.emplace(m_handlerId, std::bind(func, std::forward<ObjT>(obj), _1, _2, _3, _4));
151             return m_handlerId++;
152         }
153 
154         void operator ()(P1 arg1, P2 arg2, P3 arg3, P4 arg4)
155         {
156             for ( const auto& i : m_handlers )
157                 i.second(arg1, arg2, arg3, arg4);
158         }
159     };
160 
161     template<class P1, class P2, class P3, class P4, class P5>
162     class Event<P1, P2, P3, P4, P5, Private::NullType, Private::NullType, Private::NullType, Private::NullType, Private::NullType>
163         : public Private::EventBase<void (P1, P2, P3, P4, P5)>
164     {
165     public:
166         using Private::EventBase<void (P1, P2, P3, P4, P5)>::addHandler;
167 
168         template<class ObjT, class FuncT> int addHandler(ObjT obj, FuncT func)
169         {
170             using namespace std::placeholders;
171             m_handlers.emplace(m_handlerId, std::bind(func, std::forward<ObjT>(obj), _1, _2, _3, _4, _5));
172             return m_handlerId++;
173         }
174 
175         void operator ()(P1 arg1, P2 arg2, P3 arg3, P4 arg4, P5 arg5)
176         {
177             for ( const auto& i : m_handlers )
178                 i.second(arg1, arg2, arg3, arg4, arg5);
179         }
180     };
181 
182     template<class P1, class P2, class P3, class P4, class P5, class P6>
183     class Event<P1, P2, P3, P4, P5, P6, Private::NullType, Private::NullType, Private::NullType, Private::NullType>
184         : public Private::EventBase<void (P1, P2, P3, P4, P5, P6)>
185     {
186     public:
187         using Private::EventBase<void (P1, P2, P3, P4, P5, P6)>::addHandler;
188 
189         template<class ObjT, class FuncT> int addHandler(ObjT obj, FuncT func)
190         {
191             using namespace std::placeholders;
192             m_handlers.emplace(m_handlerId, std::bind(func, std::forward<ObjT>(obj), _1, _2, _3, _4, _5, _6));
193             return m_handlerId++;
194         }
195 
196         void operator ()(P1 arg1, P2 arg2, P3 arg3, P4 arg4, P5 arg5, P6 arg6)
197         {
198             for ( const auto& i : m_handlers )
199                 i.second(arg1, arg2, arg3, arg4, arg5, arg6);
200         }
201     };
202 
203     template<class P1, class P2, class P3, class P4, class P5, class P6, class P7>
204     class Event<P1, P2, P3, P4, P5, P6, P7, Private::NullType, Private::NullType, Private::NullType>
205         : public Private::EventBase<void (P1, P2, P3, P4, P5, P6, P7)>
206     {
207     public:
208         using Private::EventBase<void (P1, P2, P3, P4, P5, P6, P7)>::addHandler;
209 
210         template<class ObjT, class FuncT> int addHandler(ObjT obj, FuncT func)
211         {
212             using namespace std::placeholders;
213             m_handlers.emplace(m_handlerId, std::bind(func, std::forward<ObjT>(obj), _1, _2, _3, _4, _5, _6, _7));
214             return m_handlerId++;
215         }
216 
217         void operator ()(P1 arg1, P2 arg2, P3 arg3, P4 arg4, P5 arg5, P6 arg6, P7 arg7)
218         {
219             for ( const auto& i : m_handlers )
220                 i.second(arg1, arg2, arg3, arg4, arg5, arg6, arg7);
221         }
222     };
223 
224     template<class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8>
225     class Event<P1, P2, P3, P4, P5, P6, P7, P8, Private::NullType, Private::NullType>
226         : public Private::EventBase<void (P1, P2, P3, P4, P5, P6, P7, P8)>
227     {
228     public:
229         using Private::EventBase<void (P1, P2, P3, P4, P5, P6, P7, P8)>::addHandler;
230 
231         template<class ObjT, class FuncT> int addHandler(ObjT obj, FuncT func)
232         {
233             using namespace std::placeholders;
234             m_handlers.emplace(m_handlerId, std::bind(func, std::forward<ObjT>(obj), _1, _2, _3, _4, _5, _6, _7, _8));
235             return m_handlerId++;
236         }
237 
238         void operator ()(P1 arg1, P2 arg2, P3 arg3, P4 arg4, P5 arg5, P6 arg6, P7 arg7, P8 arg8)
239         {
240             for ( const auto& i : m_handlers )
241                 i.second(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
242         }
243     };
244 
245     template<class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8, class P9>
246     class Event<P1, P2, P3, P4, P5, P6, P7, P8, P9, Private::NullType>
247         : public Private::EventBase<void (P1, P2, P3, P4, P5, P6, P7, P8, P9)>
248     {
249     public:
250         using Private::EventBase<void (P1, P2, P3, P4, P5, P6, P7, P8, P9)>::addHandler;
251 
252         template<class ObjT, class FuncT> int addHandler(ObjT obj, FuncT func)
253         {
254             using namespace std::placeholders;
255             m_handlers.emplace(m_handlerId, std::bind(func, std::forward<ObjT>(obj), _1, _2, _3, _4, _5, _6, _7, _8, _9));
256             return m_handlerId++;
257         }
258 
259         void operator ()(P1 arg1, P2 arg2, P3 arg3, P4 arg4, P5 arg5, P6 arg6, P7 arg7, P8 arg8, P9 arg9)
260         {
261             for ( const auto& i : m_handlers )
262                 i.second(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9);
263         }
264     };
265 
266 
267 } // namespace Utility

测试代码

各种绑定方式
C++中事件机制的简洁实现C++中事件机制的简洁实现View Code

1 #include "Event.h"
  2 
  3 using namespace std;
  4 
  5 
  6 void f1(int, int)
  7 {
  8     puts("f1()");
  9 }
 10 
 11 struct F2
 12 {
 13     F2() { puts("F2 construct"); }
 14     F2(const F2 &) { puts("F2 copy"); }
 15     F2(F2 &&) { puts("F2 move"); }
 16     F2& operator=(const F2 &)  { puts("F2 copy assign"); return *this; }
 17     F2& operator=(F2 &&)  { puts("F2 move assign"); return *this; }
 18 
 19     void f(int, int)
 20     {
 21         puts("f2()");
 22     }
 23 
 24     void fc(int, int) const
 25     {
 26         puts("f2c()");
 27     }
 28 };
 29 
 30 struct F3
 31 {
 32     F3() { puts("F3 construct"); }
 33     F3(const F3 &) { puts("F3 copy"); }
 34     F3(F3 &&) { puts("F3 move"); }
 35     F3& operator=(const F3 &)  { puts("F3 copy assign"); return *this; }
 36     F3& operator=(F3 &&)  { puts("F3 move assign"); return *this; }
 37 
 38     void operator ()(int, int) const
 39     {
 40         puts("f3()");
 41     }
 42 };
 43 
 44 int _tmain(int argc, _TCHAR* argv[])
 45 {
 46     Utility::Event<int, int> e;
 47 
 48     // 一般函数
 49     e.addHandler(f1);
 50 
 51     int id = e.addHandler(&f1);                                    
 52     e.removeHandler(id);                                                // 移除事件处理函数
 53     
 54 
 55     // 成员函数
 56     using namespace std::placeholders;
 57 
 58     F2 f2;
 59     const F2 *pf2 = &f2;
 60 
 61     e.addHandler(bind(&F2::f, &f2, _1, _2));        // std::bind
 62     e.addHandler(&f2, &F2::f);
 63 
 64     e.addHandler(pf2, &F2::fc);                                    // 常量指针
 65     
 66     puts("----addHandler(f2, &F2::f)----");
 67     e.addHandler(f2, &F2::f);                                        // 对象拷贝构造
 68 
 69     puts("----addHandler(F2(), &F2::f)----");
 70     e.addHandler(F2(), &F2::f);                                    // 对象转移构造
 71 
 72     puts("--------");
 73 
 74 
 75     // 仿函数
 76     F3 f3;
 77     const F3 *pf3 = &f3;
 78 
 79     puts("----addHandler(f3)----");
 80     e.addHandler(f3);                                                        // 对象拷贝构造
 81 
 82     puts("----addHandler(F3())----");
 83     e.addHandler(F3());                                                    // 对象转移构造
 84     puts("--------");
 85 
 86     e.addHandler(ref(f3));                                            // 引用仿函数对象
 87     e.addHandler(ref(*pf3));                                        // 引用仿函数常量对象
 88 
 89     puts("--------");
 90 
 91     // Lambda表达式
 92     e.addHandler([](int, int) {
 93         puts("f4()");
 94     });
 95 
 96     // 激发事件
 97     e(1, 2);
 98 
 99     return 0;
100 }

原文链接: https://www.cnblogs.com/lierlier/archive/2013/02/01/cppevent.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/77372

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年2月9日 下午5:54
下一篇 2023年2月9日 下午5:55

相关推荐