I had a go at extending the system to handle static events as well.
It makes sense to use separate code; they can eventually be merged -- that will be trivial.
http://coliru.stacked-crooked.com/a/e0631620e8637786
Not quite sure what qualifies as the best Interface -- I've provided the following:
event.addStaticHandler(&handler); event.fire(1); event.removeStaticHandler(&handler); // or... uint64_t id_A = event.addStaticHandler(&handler); event.fire(2); event.removeStaticHandler(id_A); // or... event += &handler; event.fire(3); event -= &handler;
Interestingly, you can also pass a lambda, so the following also works:
uint64_t id_L = event.addStaticHandler( [](int x){ ... } ); event.fire(4); event.removeStaticHandler(id_L);
You can even cut it right down:
event += [] (int x) { ... }; event.fire(5);
The only problem is there is no way to remove that last one from event's subscriber list. I can imagine cases where this wouldn't be a problem, and it is very succinct!
π
PS Lambdas can capture, although I have no idea what happens if you add a lambda from inside some instance method that captures `this`, and then destroy the instance.
PPS I had tried to get the id to be the raw function pointer, but my technique for extracting this from a std::function seems to cause a segfault if I feed in a lambda.
PPPS complete listing:
// C++11 Static Event System // π 10.03.2016 // 1st revision #include <vector> #include <iostream> #include <algorithm> #include <string> #include <functional> using namespace std; template<class... Args> class Event { private: using F = std::function<void(Args...)>; struct Invoker { F fp; uint64_t id; }; std::vector<Invoker> staticInvokers; static void* getAddress(F f) { return (void*)*f.template target<void(*)(Args...)>(); } uint64_t counter = 0; public: void fire(Args... args) { for (auto& i : staticInvokers) i.fp(args...); } uint64_t addStaticHandler(F f) { staticInvokers.push_back(Invoker{f,counter}); return counter++; //getAddress(f); } void operator+=(F f) { addStaticHandler(f); } void removeStaticHandler(F f) { removeStaticHandler( getAddress(f) ); } void operator-=(F f) { removeStaticHandler(f); } void removeStaticHandler(void* addr) { auto to_remove = std::remove_if( staticInvokers.begin(), staticInvokers.end(), [addr](auto& item) { return Event::getAddress(item.fp) == addr; } ); staticInvokers.erase(to_remove, staticInvokers.end()); // yup std::remove_if doesn't actually do the removing (gah) } void removeStaticHandler(uint64_t id) { auto to_remove = std::remove_if( staticInvokers.begin(), staticInvokers.end(), [id](auto& item) { return item.id == id; } ); staticInvokers.erase(to_remove, staticInvokers.end()); // yup std::remove_if doesn't actually do the removing (gah) } }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - static void handler(int x) { cout << "handler hit with value: " << x << endl; } int main() { Event<int> event; event.addStaticHandler(&handler); event.fire(1); event.removeStaticHandler(&handler); // or... uint64_t id_A = event.addStaticHandler(&handler); event.fire(2); event.removeStaticHandler(id_A); // or... event += &handler; event.fire(3); event -= &handler; uint64_t id_L = event.addStaticHandler( [] (int x) { cout << "lambda hit with value: " << x << endl; } ); event.fire(4); event.removeStaticHandler(id_L); event += [] (int x) { cout << "second lambda hit with value: " << x << endl; }; event.fire(5); return 0; }