Skip to content

Instantly share code, notes, and snippets.

Last active August 24, 2023 08:13
Show Gist options
  • Star 32 You must be signed in to star a gist
  • Fork 13 You must be signed in to fork a gist
  • Save makomweb/6982207 to your computer and use it in GitHub Desktop.
Save makomweb/6982207 to your computer and use it in GitHub Desktop.
Fun with C++: implementing a pub/sub scenario using std::bind and other standard facilities. The approach is pretty similar to the well known .NET event mechanism.
#include <iostream>
#include <map>
#include <algorithm>
#include <functional>
#include <memory>
using namespace std;
class EventArgs {
virtual ~EventArgs() {}
class StringEventArgs : public EventArgs {
string payload_;
explicit StringEventArgs(const string& payload) : payload_(payload) {}
const string& Payload() const { return payload_; }
class Event {
class Callback {
void* pSender_;
const EventArgs& args_;
Callback(void* pSender, const EventArgs& args) : pSender_(pSender), args_(args) {}
void operator()(pair<long, function<void(void*, const EventArgs&)>> p) const {
p.second(pSender_, args_);
map<long, function<void(void*, const EventArgs&)>> callbacks_;
long token_ = 0;
void operator()(void* pSender, const EventArgs& args) const {
for_each(callbacks_.begin(), callbacks_.end(), Callback(pSender, args));
long Subscribe(function<void(void*, const EventArgs&)> f) {
callbacks_.insert(make_pair(token_, f));
return token_;
void Unsubscribe(long token) {
class Publisher {
Event event_;
string name_;
explicit Publisher(const string& name) : name_(name) {}
const string& Name() const { return name_; }
void Publish(const string& message) {
event_(this, StringEventArgs(message));
long Register(function<void(void*, const EventArgs&)> f) {
return event_.Subscribe(f);
void Unregister(long token) {
class Subscriber {
string name_;
explicit Subscriber(const string& name) : name_(name) {}
void OnEventReceived(void* pSender, const EventArgs& args) {
const StringEventArgs* const s = dynamic_cast<const StringEventArgs* const>(&args);
if (s == nullptr)
if (pSender == nullptr)
Publisher* p = static_cast<Publisher*>(pSender);
cout << name_.c_str() << " has received " << s->Payload().c_str() << " from " << p->Name().c_str() << endl;
namespace {
using namespace std::placeholders;
long Subscribe(Publisher& publisher, Subscriber& subscriber) {
return publisher.Register(bind(&Subscriber::OnEventReceived, &subscriber, _1, _2));
void Unsubscribe(Publisher& publisher, long token) {
class Subscription {
Publisher& publisher_;
long token_;
Subscription(Publisher& publisher, long token) : publisher_(publisher), token_(token) {
~Subscription() {
int main() {
Publisher prod("Publisher");
Subscriber sub_1("Subscriber-1");
Subscriber sub_2("Subscriber-2");
long token_1 = Subscribe(prod, sub_1);
long token_2 = Subscribe(prod, sub_2);
Unsubscribe(prod, token_1);
Unsubscribe(prod, token_2);
return 0;
Copy link

antonhristozov commented Jan 6, 2023

This is cool. I templatized it and removed the c_str() references, and it can now work with arbitrary types, not just strings.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment