Во. Версия сырая и требует обработки напи^Wмакросами. Очень легко приделать регистрацию не только методов, но и обычных функций. Также может захотеться передавать что-нибудь через сигналы (в данной версии они умеют только пинать соседей). Самый простой способ - использовать какую-нибудь абстрактную структуру или набор variant-ов. Полноценно передача параметров делается через огромные костыли с помощью шаблонов (см реализацию сигналов в boost) или с помощью препроцесора (см Qt).
| Код | #include<stdint.h> #include<string.h> #include<stdio.h>
#include<vector>
// #include<stLogger.h> #define stDebug(...) fprintf(stderr,"%s: ",__PRETTY_FUNCTION__); fprintf(stderr,__VA_ARGS__);fprintf(stderr,"\n")
class signaler { protected: class caller_iface; template<typename T>class caller; struct sig_t; typedef uint8_t member_t[sizeof(void*)*8];//buf for member pointer. buf is so large for stupid compilers like MSVC typedef std::vector<caller_iface*> dst_t;
std::vector<sig_t> sigs;
template<typename T> dst_t* __findSignal(void(T::*)());
public:
template<typename T> void __registerSignal(void(T::*)());
template<typename Tsrc,typename Tdst> void __addSlot(void(Tsrc::*)(),Tdst*,void(Tdst::*)());
template<typename T> void __emit(void(T::*)());
};
struct signaler::sig_t { member_t fnc; dst_t dst; };
class signaler::caller_iface { public: // virtual bool compare(caller_iface*)=0; //I'll need it when I want remove slots (aka disconnect) virtual void call()=0; };
template<typename T> class signaler::caller:public signaler::caller_iface { protected: T *obj; void(T::*fnc)(); public: caller(T*,void(T::*)()); void call(); };
template<typename T> signaler::caller<T>::caller(T *_obj,void(T::*_fnc)()):obj(_obj),fnc(_fnc) { }
template<typename T> void signaler::caller<T>::call() { (this->obj->*this->fnc)(); }
template<typename T> signaler::dst_t* signaler::__findSignal(void(T::*fnc)()) { for (int i=0;i<this->sigs.size();i++) if (memcmp(&fnc,this->sigs[i].fnc,sizeof(fnc))==0) return &this->sigs[i].dst; return 0; }
template<typename T> void signaler::__registerSignal(void(T::*fnc)()) { if (this->__findSignal(fnc)!=0) { stDebug("signal is already registred."); return; } struct sig_t sig; memset(sig.fnc,0,sizeof(sig,fnc)); memcpy(sig.fnc,&fnc,sizeof(fnc)); this->sigs.push_back(sig); }
template<typename Tsrc,typename Tdst> void signaler::__addSlot(void(Tsrc::*s_fnc)(),Tdst *d_obj,void(Tdst::*d_fnc)()) { dst_t *vct=this->__findSignal(s_fnc); if (vct==0) { stDebug("can not find signal."); return; } vct->push_back(new caller<Tdst>(d_obj,d_fnc)); }
template<typename T> void signaler::__emit(void(T::*fnc)()) { dst_t *vct=this->__findSignal(fnc); if (vct==0) { stDebug("can not find signal."); return; } for (int i=0;i<vct->size();i++) vct->at(i)->call(); }
class test1:public signaler { public: void sig1() {} void sig2() {} };
class test2 { public: char const *str; test2(char const *str) { this->str=str; } void slot1() { stDebug("%s",str); } };
int main() { test1 t1;
test2 t21("Hello"); test2 t22("world");
t1.__registerSignal(&test1::sig1); t1.__addSlot(&test1::sig1,&t21,&test2::slot1); t1.__addSlot(&test1::sig1,&t22,&test2::slot1);
t1.__emit(&test1::sig1);
return 0; }
|
|