samedi 19 décembre 2020

Creating generic (template) dispatcher for producer and consumer

I am trying to create a templated dispatcher to handle the registering of consumers, and pushing of data from producers. The goals are:

  1. When a user calls push(myData) a static (singleton-ish) dispatcher is used.
  2. When a user registers a callback interested in data of type T, they register their callback to the dispatcher of type T.
  3. #1 or #2 can occur first, register before push, or push before register. This is why a static/singleton-ish dispatcher is used. Also want to make sure both producers and consumers are referring to the same dispatcher.
  4. I will have many different message/data types going through the system so wanted to create a generic producer/consumer/dispatch.

This is what I have so far. It compiles fine however the callback does not work or get triggered. Names are temporary while experimenting.

main.cpp

#include "t.h"
#include <string>
#include <iostream>
/* My concrete class/data that needs to be sent out */
class A {
public:
  std::string name() const {return "A";}
};
/* Consumer callback */
void callback(const A& a);

int main() {
  A a;
  std::function<void(const A&)> f = callback;
  /* Try and register for A objects */
  reg<A>(f);
  /* Push the A object, should in theory call callback() but it doesnt */
  push(a);
}

void callback(const A& a) {
  std::cout << "I got callbacked with " << a.name() << std::endl;
}

t.h So in this example I am hoping to create a dispatcher of A objects in reg(), and then on push() use the same dispatcher to notify observers. I have print statements on the type for my debugging of this problem.

// t.h
#include <iostream>
#include <functional>
#include <vector>
#include <typeinfo>

/* Generic dispatcher of type T objects */
template<typename T>
class Dispatcher {
public:
  /* Users register a callback to get incoming T objects */
  void Register(std::function<void(const T&)> f) {
    observers_.push_back(f);
  }

  /* On push() notify all observers with the new data  */
  void Notify(const T& t) const {
    for (auto o : observers_) {
      o(t);
    }
  }
private:
  std::vector<std::function<void(const T&)>> observers_;
};

/* For creating only 1 dispatcher of type T, so push() and reg() are referring to the same object */
template<typename T>
T& Get() {
  static T t_;
  std::cout << "Get " << typeid(T).name() << std::endl;
  return t_;
}

/* Producers push new T objects */
template<typename T>
void push(const T& t) {
  std::cout << "Push " << typeid(T).name() << std::endl;
  auto d = Get<Dispatcher<T>>();
  d.Notify(t);
}

/* Consumers register for new T objects */
template<typename T>
void reg(std::function<void(const T& t)> f) {
  auto d = Get<Dispatcher<T>>();
  std::cout << "reg " << typeid(T).name() << std::endl;
  d.Register(f);
}

Aucun commentaire:

Enregistrer un commentaire