在程序中使用批量事件通知是很常用的场景,该事件分发器可以绑定多个静态与非静态函数,内部使用标准库的list和function实现,可变模板参数可以拓展到任意长度。
模仿C#中的委托,分为Events、Delegate、Action和Function。以下是继承的结构。
- Events (添加移除静态与实例事件)
- Delegate (执行事件、按实例移除或全部移除)
- Action (Delegate特化版本)
- Function (继承Delegate,实现带返回值列表的执行事件)
- Function<bool> (Function偏特化版本,实现返回值验证是否存在false)
- Delegate (执行事件、按实例移除或全部移除)
- ActionEvents (Event特化版本)
- FunctionEvents (Event特化版本)
Events作为模板需要传入返回值与形参类型,同时Events作为基类,只能使用添加事件和移除事件,并不可以执行。而执行函数是在Delegate层以上的,因为ActionEvents和FunctionEvents只是Events的具体化,Action只是Delegate的具体化,所以就可以有以下的继承关系。
- ActionEvents (Events)
- Action (Delegate)
- FunctionEvents (Events)
- Delegate
- Function
- Function<bool>
- Delegate
Events类应该实现以下几个功能:
- 添加与移除函数指针的事件(普通函数、成员静态函数与无捕获的lambda表达式)
- 添加与移除实例事件(成员实例函数)
- 通过索引来移除闭包lambda
- 提供+=与-=运算符重载(仅函数指针类型)
Delegate类功能实现:
- Invoke执行所有事件
- 按实例对象移除事件
- 移除所有事件
普通的函数指针因为在内存中仅存在一份,所以在移除时可以方便的直接对保存的函数指针进行对比。
带捕获的lambda表达式可以直接转换成std::function类型,采用索引的方式来控制:将函数保存后,返回一个自增的索引,外部可以通过这个索引来移除。或者在创建时传入一个实例对象,最后按实例移除事件。
普通的实例函数就需要使用std::bind对实例进行绑定,但是绑定后就没办法对实例和成员指针进行判断,所以使用成员指针来比较,C++的成员指针必须要求指定的类型,所以使用类模板,并通过继承来做类型擦除,类型擦除后就可以将它们保存到一起,同时取值函数也是一个模板函数,在取值时对实例进行基类至子类的转换。
所有事件的绑定绑定都会返回一个索引值,用来标示该事件,主要用于没有名字函数的移除,在单独移除事件时需要该索引值,在不需要移除单事件或移除全部的情况下该索引可以丢弃。
使用:
#include "CoreLib/Events.hpp" class EventTest { public: int cb_index; Action<int> e; void lambda_inst(int c) { std::cout << "lambda_inst callback" << std::endl; } void bind_inst(int c) { std::cout << "bind_inst callback" << std::endl; } static void static_method(int c) { std::cout << "static_method callback" << std::endl; } EventTest() { //静态lambda两种方式 e.AddListener([](int c) { std::cout << "static lambda1 callback" << std::endl; }); e += [](int c) { std::cout << "static lambda2 callback" << std::endl; }; //静态函数 e += static_method; //或 e.AddListener(static_method); //e -= static_method; 或 e.RemoveListener(static_method); //添加与移除闭包lambda方法,可以把lambda托管给this,然后最后按实例移除 this->cb_index = e.AddListener(this, [this](int c) { this->lambda_inst(c); }); //e.RemoveListenerByIndex(this->cb_index); //添加与移除成员方法 e.AddListener(this, &EventTest::bind_inst); //e.RemoveListener(this, &EventTest::bind_inst); //执行 e.Invoke(3); //移除实例中的所有事件 e.RemoveByInstance(this); //移除全部事件 e.RemoveAllListener(); } };
输出结果:
static lambda1 callback static lambda2 callback static_method callback lambda_inst callback bind_inst callback
该源码你可以在 https://github.com/JomiXedYu/JxCode.CoreLib/blob/main/CoreLib/Events.hpp 找到。
源码:
#ifndef CORELIB_EVENTS_HPP #define CORELIB_EVENTS_HPP #include <list> #include <functional> template<typename TReturn, typename... TArgs> class Events { public: using FunctionType = std::function<TReturn(TArgs...)>; using FunctionPointer = TReturn(*)(TArgs...); protected: enum class FunctionInfoType { Static, Lambda, Member }; class FunctionInfo { public: unsigned int index; FunctionInfoType type; public: FunctionInfo(const unsigned int& index, const FunctionInfoType& type) : index(index), type(type) { } public: bool operator ==(const FunctionInfo& r) { return this->index == r.index; } virtual TReturn Invoke(TArgs...) = 0; }; class StaticFunctionInfo : public FunctionInfo { public: FunctionPointer ptr; StaticFunctionInfo(const unsigned int& index, FunctionPointer ptr) : FunctionInfo(index, FunctionInfoType::Static), ptr(ptr) { } virtual TReturn Invoke(TArgs... args) override { return ptr(args...); } }; class LambdaFunctionInfo : public FunctionInfo { public: FunctionType func; void* instance; LambdaFunctionInfo( const unsigned int& index, void* instance, const FunctionType& func) : FunctionInfo(index, FunctionInfoType::Lambda), instance(instance), func(func) { } virtual TReturn Invoke(TArgs... args) override { return func(args...); } }; template<typename TObj> class MemberFunctionInfo : public FunctionInfo { public: TObj* instance; TReturn(TObj::* ptr)(TArgs...); MemberFunctionInfo( const unsigned int& index, TObj* instance, TReturn(TObj::* ptr)(TArgs...)) : FunctionInfo(index, FunctionInfoType::Member), instance(instance), ptr(ptr) { } virtual TReturn Invoke(TArgs... args) override { return (instance->*ptr)(args...); } }; protected: unsigned int index; std::list<FunctionInfo*> eventList; public: int Count() const { return this->eventList.size(); } public: Events() : index(0) {} Events(const Events& right) = delete; Events(Events&& right) = delete; ~Events() { this->RemoveAllListener(); } protected: void RemoveAllListener() { for (auto it = this->eventList.begin(); it != this->eventList.end(); it++) { delete* it; } this->eventList.clear(); } public: //static unsigned int AddListener(FunctionPointer funcPtr) { if (funcPtr == nullptr) { return 0; } this->eventList.push_back(new StaticFunctionInfo(++this->index, funcPtr)); return this->index; } //member template<typename TObj> unsigned int AddListener(TObj* obj, TReturn(TObj::* ptr)(TArgs...)) { if (obj == nullptr) { return 0; } this->eventList.push_back(new MemberFunctionInfo<TObj>(++this->index, obj, ptr)); return this->index; } //lambda template<typename TObj> unsigned int AddListener(TObj* obj, const FunctionType& func) { this->eventList.push_back(new LambdaFunctionInfo(++this->index, obj, func)); return this->index; } //static unsigned int RemoveListener(FunctionPointer funcPtr) { for (auto it = this->eventList.begin(); it != this->eventList.end(); it++) { if ((*it)->type == FunctionInfoType::Static && static_cast<StaticFunctionInfo*>(*it)->ptr == funcPtr) { auto index = (*it)->index; delete* it; this->eventList.erase(it); return index; } } return 0; } //member template<typename TObj> unsigned int RemoveListener(TObj* obj, TReturn(TObj::* ptr)(TArgs...)) { for (auto it = this->eventList.begin(); it != this->eventList.end(); it++) { if ((*it)->type == FunctionInfoType::Member && static_cast<MemberFunctionInfo<TObj>*>(*it)->instance == obj && static_cast<MemberFunctionInfo<TObj>*>(*it)->ptr == ptr) { auto index = (*it)->index; delete* it; this->eventList.erase(it); return index; } } return 0; } unsigned int RemoveListenerByIndex(unsigned int index) { if (index <= 0) { return 0; } for (auto it = this->eventList.begin(); it != this->eventList.end(); it++) { if ((*it)->index == index) { delete* it; this->eventList.erase(it); return index; } } return 0; } unsigned int operator+=(FunctionPointer ptr) { return this->AddListener(ptr); } unsigned int operator-=(FunctionPointer ptr) { return this->RemoveListener(ptr); } }; template<typename TReturn, typename... TArgs> class Delegate : public Events<TReturn, TArgs...> { using base = Events<TReturn, TArgs...>; public: void Invoke(TArgs... t) { for (auto& item : this->eventList) { item->Invoke(t...); } } void RemoveAllListener() { base::RemoveAllListener(); } //member lambda template<typename TObj> void RemoveByInstance(TObj* obj) { using MemberFunInfo = typename Events<TReturn, TArgs...>::template MemberFunctionInfo<TObj>; using LambdaFunInfo = typename Events<TReturn, TArgs...>::LambdaFunctionInfo; for (auto it = this->eventList.begin(); it != this->eventList.end(); ) { if (( (*it)->type == base::FunctionInfoType::Member && (static_cast<MemberFunInfo*>(*it))->instance == obj ) || ( (*it)->type == base::FunctionInfoType::Lambda && static_cast<LambdaFunInfo*>(*it)->instance == obj ) ) { delete* it; it = this->eventList.erase(it); } else { it++; } } } }; template<typename... TArgs> using ActionEvents = Events<void, TArgs...>; template<typename... TArgs> using Action = Delegate<void, TArgs...>; template<typename TReturn, typename... TArgs> using FunctionEvents = Events<TReturn, TArgs...>; template<typename TReturn, typename... TArgs> class Function : public Delegate<TReturn, TArgs...> { public: std::vector<TReturn> InvokeResult(TArgs... args) { std::vector<TReturn> retList; for (auto& item : this->eventList) { retList.push_back(item->Invoke(args...)); } return retList; } }; template<> class Function<bool> : public Delegate<bool> { public: std::vector<bool> InvokeResult() { std::vector<bool> retList; for (auto& item : this->eventList) { retList.push_back(item->Invoke()); } return retList; } bool IsValidReturnInvoke() { for (const bool& item : this->InvokeResult()) { if (!item) return false; } return true; } }; #endif // !CORELIB_EVENTS_HPP
文章评论