Skip to content

Instantly share code, notes, and snippets.

@lbargaoanu
Created November 15, 2016 14:21
Show Gist options
  • Save lbargaoanu/6f0efa41dc2d190da7f6dc9c282c01c9 to your computer and use it in GitHub Desktop.
Save lbargaoanu/6f0efa41dc2d190da7f6dc9c282c01c9 to your computer and use it in GitHub Desktop.
#include "stdafx.h"
#include <iostream>
#include <functional>
#include <tuple>
#include <utility>
#include <vector>
class IActiveObject {
public:
void Post(std::function<void(void)> handler)
{
handler();
}
};
template<typename Events> class EventSource {
private:
using EventTable = typename Events::EventTable;
public:
// Connects event handler.
template<size_t Event, typename Handler>
void Connect(Handler&& handler) {
auto& event = std::get<Event>(signals_);
event.handlers.emplace_back(std::forward<Handler>(handler), nullptr);
}
protected:
EventSource() = default;
// Generates n-ary signal.
template<size_t Event, typename... Args>
void FireEvent(Args&&... args) const {
std::get<Event>(signals_).Fire(std::forward<Args>(args)...);
}
private:
mutable EventTable signals_;
};
template<typename Signature> struct EventHandler
{
std::function<Signature> handler;
IActiveObject* activeObject;
EventHandler(std::function<Signature> handler, IActiveObject* activeObject) : handler(handler), activeObject(activeObject)
{
}
template<typename... Args>
void Fire(Args&&... args) const
{
IActiveObject localActiveObject;
localActiveObject.Post([&]() {
handler(std::forward<Args>(args)...);
});
}
};
template<typename Signature> struct EventDefinition
{
std::vector<EventHandler<Signature>> handlers;
template<typename... Args>
void Fire(Args&&... args) const
{
for (auto& item : handlers)
{
item.Fire(std::forward<Args>(args)...);
}
}
};
//-----------------------------------------------------------------------------
// Example usage.
//-----------------------------------------------------------------------------
struct MyEvents {
enum Event { EventA, EventB };
using EventADef = EventDefinition<void()>;
using EventBDef = EventDefinition<void(int, int)>;
using EventTable = std::tuple<
EventADef,
EventBDef
>;
};
class MySource : public EventSource<MyEvents> {
public:
void EmitEventA() {
std::cout << "EventA signal generated." << std::endl;
FireEvent<MyEvents::EventA>();
}
int EmitEventB(int foo, int bar) {
std::cout << "EventB signal generated. foo = " << foo << " bar = " << bar << std::endl;
FireEvent<MyEvents::EventB>(foo, bar);
return 0;
}
};
class MyListener {
public:
void OnEventA() {
std::cout << "OnEventA handler called." << std::endl;
}
int OnEventB(int foo, int bar) {
std::cout << "OnEventB handler called. foo = " << foo << " bar = " << bar << std::endl;
return foo * 2;
}
};
int main() {
MySource event_source;
MyListener event_listener;
// Connect event handlers.
event_source.Connect<MyEvents::EventA>([&]() {
event_listener.OnEventA();
});
event_source.Connect<MyEvents::EventA>([&]() {
event_listener.OnEventA();
});
event_source.Connect<MyEvents::EventB>([&](int foo, int bar) {
return event_listener.OnEventB(foo, bar);
});
// Fire events.
event_source.EmitEventA();
event_source.EmitEventB(3, 4);
event_source.EmitEventB(8, 9);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment