思路 用变长参数模板定义类,用单链表保存函数对象。使用了std::bind
和std::integer_sequence
自动生成占位符来简化成员函数的绑定
实现 Event.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 #pragma once #include <functional> #include <forward_list> template <int N>struct Placeholder { static_assert (N > 0 , "invalid placeholder index" ); }; namespace std { template <int N> struct is_placeholder < Placeholder<N>> : integral_constant<int , N> {}; } template <typename ... Args>class Event {public : using Function = std ::function<void (Args...)>; using Container = std ::forward_list<Function>; using Iterator = typename Container::const_iterator; Iterator Add (Function func) { _funcs.emplace_front(func); return _funcs.cbegin(); } template <typename T> Iterator Add (void (T::* func)(Args...), T& obj) { return _add(func, obj, std ::make_integer_sequence<int , sizeof ...(Args)>{}); } void Remove (Iterator iterator) { if (iterator == _funcs.cbegin()) { _funcs.pop_front(); return ; } auto lastIt = _funcs.cbegin(), end = _funcs.cend(); for (auto curIt = _funcs.cbegin(); curIt != end; ) { lastIt = curIt++; if (curIt == iterator) { _funcs.erase_after(lastIt); break ; } } } void Clear () { _funcs.clear(); } void Invoke (Args... arg) { if (Empty()) { return ; } for (auto & f : _funcs) { f(std ::forward<Args>(arg)...); } } bool Empty () const { return _funcs.empty(); } void operator () (Args... arg) { Invoke(std ::forward<Args>(arg)...); } auto operator +=(Function func) { return Add(func); } void operator -=(Iterator iterator) { Remove(iterator); } operator bool () { return !Empty(); } private : Container _funcs; template <typename T, int ... I> auto _add(void (T::* func)(Args...), T& obj, std ::integer_sequence<int , I...>) { return Add(std ::bind(func, std ::ref(obj), Placeholder<I + 1 >{}...)); } };
使用 一些声明
1 2 3 4 5 6 7 8 9 10 11 12 using ArgType = const std ::string &;void PrintMessage (ArgType arg, char name) { std ::cout << arg << ": " << name << std ::endl ; } class Test {public : Test(char c) : name(c) {} void f (ArgType var) { PrintMessage(var, name); } char name; };
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 Event<ArgType> onChanged; Test t{ 't' }; const auto f = [](ArgType var) { PrintMessage(var, 'f' ); };const auto g = [](ArgType var) { PrintMessage(var, 'g' ); };auto tItor = onChanged.Add(&Test::f, t);auto fItor = onChanged.Add(f);auto gItor = onChanged.Add(g);onChanged("Add all" ); onChanged.Remove(fItor); onChanged("Remove f" ); onChanged.Clear(); onChanged("Clear" );