事件模型是被广泛使用的好东西,但是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
完整代码
代码下载
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
测试代码
各种绑定方式
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
非原创文章文中已经注明原地址,如有侵权,联系删除
关注公众号【高性能架构探索】,第一时间获取最新文章
转载文章受原作者版权保护。转载请注明原作者出处!