Created
March 22, 2021 01:40
-
-
Save wangzhankun/00b01b8fb96105b1b612e0ce53d9b18e to your computer and use it in GitHub Desktop.
C++事件机制
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include <map> | |
#include <functional> | |
namespace Utility | |
{ | |
namespace Private | |
{ | |
struct NullType | |
{ | |
}; | |
template <class HandlerT> | |
class EventBase | |
{ | |
public: | |
EventBase() : m_handlerId(0) {} | |
template <class FuncT> | |
int addHandler(FuncT func) | |
{ | |
m_handlers.emplace(m_handlerId, std::forward<FuncT>(func)); | |
return m_handlerId++; | |
} | |
void removeHandler(int handlerId) | |
{ | |
m_handlers.erase(handlerId); | |
} | |
protected: | |
int m_handlerId; | |
std::map<int, std::function<HandlerT>> m_handlers; | |
}; | |
} | |
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> | |
class Event | |
: public Private::EventBase<void(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10)> | |
{ | |
public: | |
using Private::EventBase<void(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10)>::addHandler; | |
template <class ObjT, class FuncT> | |
int addHandler(ObjT obj, FuncT func) | |
{ | |
using namespace std::placeholders; | |
m_handlers.emplace(m_handlerId, std::bind(func, std::forward<ObjT>(obj), _1, _2, _3, _4, _5, _6, _7, _8, _9, _10)); | |
return m_handlerId++; | |
} | |
void operator()(P1 arg1, P2 arg2, P3 arg3, P4 arg4, P5 arg5, P6 arg6, P7 arg7, P8 arg8, P9 arg9, P10 arg10) | |
{ | |
for (const auto &i : m_handlers) | |
i.second(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10); | |
} | |
}; | |
template <> | |
class Event<Private::NullType, Private::NullType, Private::NullType, Private::NullType, Private::NullType, Private::NullType, Private::NullType, Private::NullType, Private::NullType, Private::NullType> | |
: public Private::EventBase<void()> | |
{ | |
public: | |
using Private::EventBase<void()>::addHandler; | |
template <class ObjT, class FuncT> | |
int addHandler(ObjT const obj, FuncT func) | |
{ | |
m_handlers.emplace(m_handlerId, std::bind(func, obj)); | |
return m_handlerId++; | |
} | |
void operator()() | |
{ | |
for (const auto &i : m_handlers) | |
i.second(); | |
} | |
}; | |
template <class P1> | |
class Event<P1, Private::NullType, Private::NullType, Private::NullType, Private::NullType, Private::NullType, Private::NullType, Private::NullType, Private::NullType, Private::NullType> | |
: public Private::EventBase<void(P1)> | |
{ | |
public: | |
using Private::EventBase<void(P1)>::addHandler; | |
template <class ObjT, class FuncT> | |
int addHandler(ObjT obj, FuncT func) | |
{ | |
using namespace std::placeholders; | |
m_handlers.emplace(m_handlerId, std::bind(func, std::forward<ObjT>(obj), _1)); | |
return m_handlerId++; | |
} | |
void operator()(P1 arg1) | |
{ | |
for (const auto &i : m_handlers) | |
i.second(arg1); | |
} | |
}; | |
template <class P1, class P2> | |
class Event<P1, P2, Private::NullType, Private::NullType, Private::NullType, Private::NullType, Private::NullType, Private::NullType, Private::NullType, Private::NullType> | |
: public Private::EventBase<void(P1, P2)> | |
{ | |
public: | |
using Private::EventBase<void(P1, P2)>::addHandler; | |
template <class ObjT, class FuncT> | |
int addHandler(ObjT obj, FuncT func) | |
{ | |
using namespace std::placeholders; | |
m_handlers.emplace(m_handlerId, std::bind(func, std::forward<ObjT>(obj), _1, _2)); | |
return m_handlerId++; | |
} | |
void operator()(P1 arg1, P2 arg2) | |
{ | |
for (const auto &i : m_handlers) | |
i.second(arg1, arg2); | |
} | |
}; | |
template <class P1, class P2, class P3> | |
class Event<P1, P2, P3, Private::NullType, Private::NullType, Private::NullType, Private::NullType, Private::NullType, Private::NullType, Private::NullType> | |
: public Private::EventBase<void(P1, P2, P3)> | |
{ | |
public: | |
using Private::EventBase<void(P1, P2, P3)>::addHandler; | |
template <class ObjT, class FuncT> | |
int addHandler(ObjT obj, FuncT func) | |
{ | |
using namespace std::placeholders; | |
m_handlers.emplace(m_handlerId, std::bind(func, std::forward<ObjT>(obj), _1, _2, _3)); | |
return m_handlerId++; | |
} | |
void operator()(P1 arg1, P2 arg2, P3 arg3) | |
{ | |
for (const auto &i : m_handlers) | |
i.second(arg1, arg2, arg3); | |
} | |
}; | |
template <class P1, class P2, class P3, class P4> | |
class Event<P1, P2, P3, P4, Private::NullType, Private::NullType, Private::NullType, Private::NullType, Private::NullType, Private::NullType> | |
: public Private::EventBase<void(P1, P2, P3, P4)> | |
{ | |
public: | |
using Private::EventBase<void(P1, P2, P3, P4)>::addHandler; | |
template <class ObjT, class FuncT> | |
int addHandler(ObjT obj, FuncT func) | |
{ | |
using namespace std::placeholders; | |
m_handlers.emplace(m_handlerId, std::bind(func, std::forward<ObjT>(obj), _1, _2, _3, _4)); | |
return m_handlerId++; | |
} | |
void operator()(P1 arg1, P2 arg2, P3 arg3, P4 arg4) | |
{ | |
for (const auto &i : m_handlers) | |
i.second(arg1, arg2, arg3, arg4); | |
} | |
}; | |
template <class P1, class P2, class P3, class P4, class P5> | |
class Event<P1, P2, P3, P4, P5, Private::NullType, Private::NullType, Private::NullType, Private::NullType, Private::NullType> | |
: public Private::EventBase<void(P1, P2, P3, P4, P5)> | |
{ | |
public: | |
using Private::EventBase<void(P1, P2, P3, P4, P5)>::addHandler; | |
template <class ObjT, class FuncT> | |
int addHandler(ObjT obj, FuncT func) | |
{ | |
using namespace std::placeholders; | |
m_handlers.emplace(m_handlerId, std::bind(func, std::forward<ObjT>(obj), _1, _2, _3, _4, _5)); | |
return m_handlerId++; | |
} | |
void operator()(P1 arg1, P2 arg2, P3 arg3, P4 arg4, P5 arg5) | |
{ | |
for (const auto &i : m_handlers) | |
i.second(arg1, arg2, arg3, arg4, arg5); | |
} | |
}; | |
template <class P1, class P2, class P3, class P4, class P5, class P6> | |
class Event<P1, P2, P3, P4, P5, P6, Private::NullType, Private::NullType, Private::NullType, Private::NullType> | |
: public Private::EventBase<void(P1, P2, P3, P4, P5, P6)> | |
{ | |
public: | |
using Private::EventBase<void(P1, P2, P3, P4, P5, P6)>::addHandler; | |
template <class ObjT, class FuncT> | |
int addHandler(ObjT obj, FuncT func) | |
{ | |
using namespace std::placeholders; | |
m_handlers.emplace(m_handlerId, std::bind(func, std::forward<ObjT>(obj), _1, _2, _3, _4, _5, _6)); | |
return m_handlerId++; | |
} | |
void operator()(P1 arg1, P2 arg2, P3 arg3, P4 arg4, P5 arg5, P6 arg6) | |
{ | |
for (const auto &i : m_handlers) | |
i.second(arg1, arg2, arg3, arg4, arg5, arg6); | |
} | |
}; | |
template <class P1, class P2, class P3, class P4, class P5, class P6, class P7> | |
class Event<P1, P2, P3, P4, P5, P6, P7, Private::NullType, Private::NullType, Private::NullType> | |
: public Private::EventBase<void(P1, P2, P3, P4, P5, P6, P7)> | |
{ | |
public: | |
using Private::EventBase<void(P1, P2, P3, P4, P5, P6, P7)>::addHandler; | |
template <class ObjT, class FuncT> | |
int addHandler(ObjT obj, FuncT func) | |
{ | |
using namespace std::placeholders; | |
m_handlers.emplace(m_handlerId, std::bind(func, std::forward<ObjT>(obj), _1, _2, _3, _4, _5, _6, _7)); | |
return m_handlerId++; | |
} | |
void operator()(P1 arg1, P2 arg2, P3 arg3, P4 arg4, P5 arg5, P6 arg6, P7 arg7) | |
{ | |
for (const auto &i : m_handlers) | |
i.second(arg1, arg2, arg3, arg4, arg5, arg6, arg7); | |
} | |
}; | |
template <class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8> | |
class Event<P1, P2, P3, P4, P5, P6, P7, P8, Private::NullType, Private::NullType> | |
: public Private::EventBase<void(P1, P2, P3, P4, P5, P6, P7, P8)> | |
{ | |
public: | |
using Private::EventBase<void(P1, P2, P3, P4, P5, P6, P7, P8)>::addHandler; | |
template <class ObjT, class FuncT> | |
int addHandler(ObjT obj, FuncT func) | |
{ | |
using namespace std::placeholders; | |
m_handlers.emplace(m_handlerId, std::bind(func, std::forward<ObjT>(obj), _1, _2, _3, _4, _5, _6, _7, _8)); | |
return m_handlerId++; | |
} | |
void operator()(P1 arg1, P2 arg2, P3 arg3, P4 arg4, P5 arg5, P6 arg6, P7 arg7, P8 arg8) | |
{ | |
for (const auto &i : m_handlers) | |
i.second(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); | |
} | |
}; | |
template <class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8, class P9> | |
class Event<P1, P2, P3, P4, P5, P6, P7, P8, P9, Private::NullType> | |
: public Private::EventBase<void(P1, P2, P3, P4, P5, P6, P7, P8, P9)> | |
{ | |
public: | |
using Private::EventBase<void(P1, P2, P3, P4, P5, P6, P7, P8, P9)>::addHandler; | |
template <class ObjT, class FuncT> | |
int addHandler(ObjT obj, FuncT func) | |
{ | |
using namespace std::placeholders; | |
m_handlers.emplace(m_handlerId, std::bind(func, std::forward<ObjT>(obj), _1, _2, _3, _4, _5, _6, _7, _8, _9)); | |
return m_handlerId++; | |
} | |
void operator()(P1 arg1, P2 arg2, P3 arg3, P4 arg4, P5 arg5, P6 arg6, P7 arg7, P8 arg8, P9 arg9) | |
{ | |
for (const auto &i : m_handlers) | |
i.second(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9); | |
} | |
}; | |
} // namespace Utility |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "Event.h" | |
using namespace std; | |
void f1(int, int) | |
{ | |
puts("f1()"); | |
} | |
struct F2 | |
{ | |
F2() { puts("F2 construct"); } | |
F2(const F2 &) { puts("F2 copy"); } | |
F2(F2 &&) { puts("F2 move"); } | |
F2 &operator=(const F2 &) | |
{ | |
puts("F2 copy assign"); | |
return *this; | |
} | |
F2 &operator=(F2 &&) | |
{ | |
puts("F2 move assign"); | |
return *this; | |
} | |
void f(int, int) | |
{ | |
puts("f2()"); | |
} | |
void fc(int, int) const | |
{ | |
puts("f2c()"); | |
} | |
}; | |
struct F3 | |
{ | |
F3() { puts("F3 construct"); } | |
F3(const F3 &) { puts("F3 copy"); } | |
F3(F3 &&) { puts("F3 move"); } | |
F3 &operator=(const F3 &) | |
{ | |
puts("F3 copy assign"); | |
return *this; | |
} | |
F3 &operator=(F3 &&) | |
{ | |
puts("F3 move assign"); | |
return *this; | |
} | |
void operator()(int, int) const | |
{ | |
puts("f3()"); | |
} | |
}; | |
int _tmain(int argc, _TCHAR *argv[]) | |
{ | |
Utility::Event<int, int> e; | |
// 一般函数 | |
e.addHandler(f1); | |
int id = e.addHandler(&f1); | |
e.removeHandler(id); // 移除事件处理函数 | |
// 成员函数 | |
using namespace std::placeholders; | |
F2 f2; | |
const F2 *pf2 = &f2; | |
e.addHandler(bind(&F2::f, &f2, _1, _2)); // std::bind | |
e.addHandler(&f2, &F2::f); | |
e.addHandler(pf2, &F2::fc); // 常量指针 | |
puts("----addHandler(f2, &F2::f)----"); | |
e.addHandler(f2, &F2::f); // 对象拷贝构造 | |
puts("----addHandler(F2(), &F2::f)----"); | |
e.addHandler(F2(), &F2::f); // 对象转移构造 | |
puts("--------"); | |
// 仿函数 | |
F3 f3; | |
const F3 *pf3 = &f3; | |
puts("----addHandler(f3)----"); | |
e.addHandler(f3); // 对象拷贝构造 | |
puts("----addHandler(F3())----"); | |
e.addHandler(F3()); // 对象转移构造 | |
puts("--------"); | |
e.addHandler(ref(f3)); // 引用仿函数对象 | |
e.addHandler(ref(*pf3)); // 引用仿函数常量对象 | |
puts("--------"); | |
// Lambda表达式 | |
e.addHandler([](int, int) { | |
puts("f4()"); | |
}); | |
// 激发事件 | |
e(1, 2); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment