TL; DR:模板化事件存在订阅冲突和取消订阅的问题。存储数据的方法使比较变得困难,并且几乎不可能从基础转换为派生。
经过一段时间的工作,我试图重新熟悉c ++的基础知识,为此,我决定编写一个模仿c#的System.Action类功能的事件系统。
到目前为止,我已经编写了一个函子类,其中包含模板成员函子的向量,但是我遇到的主要问题是解决冲突,并取消订阅该事件。
我最初的想法是比较模板化成员函数指针的内存地址,但是由于向量保存对基类的引用,而该基类不依赖于成员函数类型,因此我在访问该数据进行比较时遇到了麻烦
我希望可以将成员函数的内存地址转换为整数并将其存储在基类中,但是这种类型的转换是非法的。
我还考虑过在派生类中重载==运算符,但是由于事情是如何进行模板化的,所以从基数到派生的转换似乎是不可能的。
我确实考虑过返回对迭代器的引用来解决取消订阅的问题,但这有一些问题。 1)重复订阅的问题仍然存在。 2)[我不确定是否确实如此],但是从向量中删除索引可能会使用户存储为订阅函数句柄的所有迭代器无效。
我知道一个简单的解决方案可能是使用std :: function包装这些成员函数,然后将std :: function :: target与我试图从偶数订阅/取消订阅的函数进行比较。但是,练习的目的是要解决此问题,而不使用该语言中存在的任何实用程序类。
这里是事件系统的头文件,因此您可以了解我为该系统采用的体系结构方法。
#include <vector>
template <class ...Args>
class EventDataBase
{
public:
virtual void Invoke(Args ...arg) = NULL;
};
template<class T, class ...Args>
class EventData : public EventDataBase<Args...>
{
private:
T *_instance;
void (T::*_method)(Args ...arg);
public:
EventData(T *instance, void (T::*method)(Args ...arg));
void Invoke(Args ...arg);
};
template<class ...Args>
class Event
{
private:
std::vector<EventDataBase<Args...>*> _subscribedReceivers;
public:
template<class T>
void Subscribe(T *instance, void (T::*method)(Args ...arg));
template<class T>
void Unsubscribe(void (T::*method)(Args ...arg));
void Invoke(Args ...arg);
};