lundi 22 mai 2017

How do do or emulate templatised std::functions in C++

Following is a basic instance of what I am doing in my C++ program. I have a list of listeners which are all std::functions. I have a concept DataType which means what kind of data the listener is interested in. The idea here is the same as publish-subscribe pattern. A method interested in certain kind of data should be able to add itself to the list of listeners using AddListener. Some methods are added & they receive a callback whenever required.

The program works fine !!

#include <iostream>
#include <functional>
#include <vector>
#include <string>

enum class DataType {
  Type_1,
  Type_2
  // and so on
};

typedef std::function<void(std::pair<DataType, std::string>)>   MyListenerType;

//template <typename T>
//typedef std::function<void(T>)>   MyListenerType;
// How can I emulate the above so that a method passing any kind of primitive data-type namely "int, bool, float or double" can be added into
// my vector of listners.


std::vector<MyListenerType>      my_data_listeners_1;
std::vector<MyListenerType>      my_data_listeners_2;

void ListenerMethod_Instance_1(std::pair<DataType, std::string> information) {

  DataType data_type = information.first;
  std::string message = information.second;
  std::cout << "ListenerMethod_Instance_1 called with message " << message << "\n";
}

void ListenerMethod_Instance_2(std::pair<DataType, std::string> information) {

  DataType data_type = information.first;
  std::string message = information.second;
  std::cout << "ListenerMethod_Instance_2 called with message " << message << "\n";
}

void AddListener (MyListenerType listener, DataType type_of_interest) {

  if (DataType::Type_1 == type_of_interest) {
    my_data_listeners_1.push_back(listener);
    std::cout << "Added a method instance for DataType::Type_1" << "\n";
  }
  else if (DataType::Type_2 == type_of_interest) {
    my_data_listeners_2.push_back(listener);
    std::cout << "Added a method instance for DataType::Type_2" << "\n";
  }
  else {
    std::cout << "Listener type not supported" << "\n";
  }
}

void CallAllListnersWhohaveSuscribed() {

  if (!my_data_listeners_1.empty()) {
    std::string send_message_1 = "some message 123";
    std::pair <DataType, std::string> info_to_send_1 = std::make_pair (DataType::Type_1, send_message_1);
    for(auto const  &listener : my_data_listeners_1) {
      listener(info_to_send_1);
    }
  }

  if (!my_data_listeners_2.empty()) {
    std::string send_message_2 = "some message 456";
    std::pair <DataType, std::string> info_to_send_2 = std::make_pair (DataType::Type_2, send_message_2);
    for(auto const  &listener : my_data_listeners_2) {
      listener(info_to_send_2);
    }
  }
}

int main() {

  // Add ListenerMethod_Instance_1 for instance
  DataType data_type_1 = DataType::Type_1;
  auto listener_instance_1 = std::bind(ListenerMethod_Instance_1, std::placeholders::_1);
  AddListener(listener_instance_1, data_type_1);

  // Add ListenerMethod_Instance_2 for instance
  DataType data_type_2 = DataType::Type_2;
  auto listener_instance_2 = std::bind(ListenerMethod_Instance_2, std::placeholders::_1);
  AddListener(listener_instance_2, data_type_2);

  CallAllListnersWhohaveSuscribed();
  return 0;
}

Following is the output of the program:

./stdFunctionTest
Added a method instance for DataType::Type_1
Added a method instance for DataType::Type_2
ListenerMethod_Instance_1 called with message some message 123
ListenerMethod_Instance_2 called with message some message 456

But here is how I want to modify & struggling with. The caveat is that every ListenerMethod_Instance_1 & ListenerMethod_Instance_2 have to parse the pair to get their info which I don't want to. I want to enable a method of any C++ primitive data type be it "int, bool, float or double" to be able to be added into the listeners vector & receive the callback. For example following method should be "add-able" into AddListener. Looking at this link here looks some

void ListenerMethod_Instance_3(int integer_data) {

  std::cout << "ListenerMethod_Instance_3 called with integer_data " << integer_data << "\n";
}

So, basically how can I achieve templates functionality with std::functions ?

Aucun commentaire:

Enregistrer un commentaire