Skip to content

Instantly share code, notes, and snippets.

@gubser
Last active April 15, 2021 12:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gubser/4db81c342ff68a7246cfd743bc8a97ac to your computer and use it in GitHub Desktop.
Save gubser/4db81c342ff68a7246cfd743bc8a97ac to your computer and use it in GitHub Desktop.
Simple observer pattern in modern C++ without pointers.
#ifndef UTIL_SUBJECT_H
#define UTIL_SUBJECT_H
#include <memory>
#include <forward_list>
#include <functional>
/**
* Simple observer pattern in modern C++ without pointers.
* Register functions with make_observer() and call notify() to call them.
* Note: Functions are called from the thread that calls notify().
*/
template <typename... Args>
class Subject
{
public:
typedef std::shared_ptr<std::function<void(Args...)>> Observer;
Subject() {}
void notify(const Args &...args)
{
bool cleanup = false;
for (const auto &observer_weak : m_observers)
{
if (const auto &observer_function = observer_weak.lock())
{
(*observer_function)(args...);
}
else
{
// weak pointer expired, do a cleanup round
cleanup = true;
}
}
if (cleanup)
{
m_observers.remove_if([](auto observer) { return observer.expired(); });
}
}
/**
* Register a function as observer. Keep the returned shared_ptr around as long as you want
* the function to be called.
*/
Observer makeObserver(std::function<void(Args...)> observerFunction)
{
auto observer = std::make_shared<std::function<void(Args...)>>(observerFunction);
m_observers.emplace_front(observer);
return observer;
}
private:
std::forward_list<std::weak_ptr<std::function<void(Args...)>>> m_observers;
};
#endif // UTIL_SUBJECT_H
#include <iostream>
#include "subject.h"
void fun1(int x, std::string s) {
std::cout << "fun1: " << x << " " << s << std::endl;
}
void fun2(int x, std::string s) {
std::cout << "fun2: " << x << " " << s << std::endl;
}
int main() {
Subject<int, std::string> s;
s.notify(0, "by none");
{
auto o1 = s.makeObserver(fun1);
s.notify(1, "by fun1");
{
auto o2 = s.makeObserver(fun2);
s.notify(2, "by fun1 and fun2");
}
s.notify(3, "only by fun1 again");
}
s.notify(4, "none");
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment