Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <functional>
- #include <vector>
- #include <tuple>
- template<typename ... Funcs>
- class Observable
- {
- public:
- using ObserverList = std::tuple<std::vector<std::function<Funcs>>...>;
- template<unsigned int eventidx, typename Callable>
- void AttachObserver(Callable c)
- {
- std::get<eventidx>(observers).push_back(c);
- }
- template<unsigned int eventidx, typename ... T>
- void NotifyObserversOfEvent(T ... args)
- {
- for(auto f: std::get<eventidx>(observers))
- {
- f(std::forward<T>(args)...);
- }
- }
- private:
- ObserverList observers;
- };
- #include <iostream>
- #include <functional>
- #include <vector>
- #include "observable.h"
- class A : public Observable<
- void(void),
- void(int,std::string),
- void(int,int),
- >
- {
- public:
- enum Event : unsigned
- {
- Event0,
- Event1,
- Event2
- };
- private:
- int a;
- std::string s;
- };
- class B
- {
- public:
- void EventZeroHappened()
- {
- std::cout << "B has observed event zeron";
- }
- void EventOneHappened(int a, std::string s)
- {
- std::cout << "B has observed event one with params: " << a << " and " << """ << s << """ <<'n';
- }
- void EventTwoHappened(int a, int b)
- {
- std::cout << "B has observed event two with params: " << a << " and " << b <<'n';
- }
- };
- int main()
- {
- A a;
- B b;
- a.AttachObserver<A::Event::Event0>([&b](){b.EventZeroHappened();});
- a.AttachObserver<A::Event::Event1>([&b](int i, std::string s){b.EventOneHappened(i,s);});
- a.AttachObserver<A::Event::Event2>([&b](int i, int j){b.EventTwoHappened(i,j);});
- a.NotifyObserversOfEvent<A::Event::Event0>();
- a.NotifyObserversOfEvent<A::Event::Event1>(37,"Hello There");
- a.NotifyObserversOfEvent<A::Event::Event2>(182,150);
- }
- class PolymorphicBehavior {
- class Concept {
- // here are the virtual functions
- };
- template <typename ConcreteType>
- class Object {
- // here are concrete implementations of the functions
- // The class encapsulates type information
- private:
- ConcreteType value;
- };
- public:
- template <typename ConcreteType>
- PolymorphicBehavior(const ConcreteType& ct) : ptr(new Object<ConcreteType>(ct)) {}
- private:
- Concept* ptr;
- };
- #include <iostream>
- #include <vector>
- #include <memory>
- #include <tuple>
- #include <any>
- #include <functional>
- //deducing the tuple type from the function type
- // e.g: std::function<void(float, double)> => std::tuple<float, double>
- template <typename T>
- struct tuple_desc;
- template <typename R, typename... Args>
- struct tuple_desc<std::function<R(Args...)>> {
- using type = std::tuple<Args...>;
- };
- // deducing the function signature from the callable
- template <typename Callable>
- using function_class = decltype(std::function(std::declval<Callable>()));
- class Observable {
- class Observable_model { // type neutral hook
- public:
- virtual void notify(unsigned event_number, std::any& argument_wrapper) = 0;
- virtual ~Observable_model() = default;
- };
- template <typename Callback>
- class Observable_object : public Observable_model { // stores concrete type information
- public:
- Observable_object(unsigned event_class, const Callback& cbk) : event_class(event_class), callback(cbk) {}
- void notify(unsigned event_number, std::any& argument_wrapper) override {
- using Arg_tuple = typename tuple_desc<decltype(this->callback)>::type; // so tuple<int, float> for [](int a, float b) { /*...*/ }
- if (event_number == event_class) { // dynamic dispatch
- std::apply(callback, std::any_cast<Arg_tuple> (argument_wrapper));
- }
- }
- private:
- unsigned event_class;
- function_class<Callback> callback;
- };
- public:
- template <typename Callback>
- void attach(unsigned event_class, Callback&& callback) {
- auto new_obj = std::make_unique<Observable_object<Callback>>(event_class, callback);
- observations.push_back(std::move(new_obj));
- }
- template <typename... Args>
- void notify(unsigned event_number, Args&&... args) {
- std::tuple<Args...> arg_tuple(std::forward<Args>(args)...);
- std::any argument_wrapper(arg_tuple); // argument type erasure
- for (auto& obs : observations) obs->notify(event_number, argument_wrapper);
- }
- private:
- std::vector<std::unique_ptr<Observable_model>> observations;
- };
- // testing the interface;
- enum { WILDLIFE = 0, MACHINES = 1 };
- struct Buzzer {
- void go(int h) { std::cout << "drrrr... drrrr... it's " << h << " a.m, time to wake up!n"; }
- };
- struct Coffee_machine {
- void make_coffee(int h) { if (h == 7) std::cout << "time to make coffee!n"; else std::cout << "no coffee yet baby!n"; }
- };
- struct Rooster {
- void sing() { std::cout << "Cocorico!n"; }
- };
- struct Vampire {
- void bury() { std::cout << "Bye! I'll be in my grave!n"; }
- };
- struct Sun : public Observable {
- void rise() {
- std::cout << "Waouh, the sun rises!n";
- notify(0);
- notify(1, 6);
- }
- };
- int main() {
- Sun sun;
- Buzzer buzzer;
- Rooster rooster;
- Vampire vampire;
- Coffee_machine coffee_machine;
- sun.attach(WILDLIFE, [&rooster] {rooster.sing();});
- sun.attach(WILDLIFE, [&vampire] {vampire.bury();});
- sun.attach(MACHINES, [&buzzer](int h) {buzzer.go(h);});
- sun.attach(MACHINES, [&coffee_machine](int h) {coffee_machine.make_coffee(h);});
- sun.rise();
- }
Add Comment
Please, Sign In to add comment