簡體   English   中英

如何在C ++中模擬templatised std :: function

[英]How emulate a templatised std::function in C++

以下是我在C++程序中所做的基本實例。 我有一個監聽器列表,它們都是std::function s。 我有一個概念DataType ,它意味着聽眾感興趣的是什么類型的數據。這里的想法與發布 - 訂閱模式相同。 對某種數據感興趣的方法應該能夠使用AddListener將自己添加到偵聽器列表中。 添加了一些方法,並在需要時接收回調。

該程序工作正常!!

#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;
}

以下是該計划的輸出:

./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

但這就是我想要修改和掙扎的方式。 需要注意的是,每個ListenerMethod_Instance_1ListenerMethod_Instance_2都必須解析該對以獲取我不想要的信息。 我想啟用任何C ++原始數據類型的方法,無論是“int,bool,float還是double”,都可以添加到偵聽器向量中並接收回調 例如,以下方法應該“添加”到AddListener

void ListenerMethod_Instance_3(int integer_data) {

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

看這個鏈接在某種程度上看起來有點可能。 但是我在努力使它適應我的用例。 請建議。

那么,基本上我如何用std::function s實現模板功能呢?

struct anything_view_t {
  void* ptr=0;
  template<class T, std::enable_if_t<!std::is_same<anything_view_t, std::decay_t<T>>{}, int> =0>
  anything_view_t(T&&t):ptr(std::addressof(t)){}
  anything_view_t()=default;
  anything_view_t(anything_view_t const&)=default;
  anything_view_t& operator=(anything_view_t const&)=default;
  template<class T>
  operator T() const { return *static_cast<T*>(ptr); }
};

這是一種非常不安全的類型擦除視圖。

struct any_callbacks {
  std::unordered_map<std::type_index, std::vector<std::function<void(anything_view_t)>>> table;
  template<class T>
  void add_callback( std::function<void(T)> f ){
    table[typeid(T)].push_back(f);
  }
  template<class T>
  void invoke_callbacks(T t) const {
    auto it = table.find(typeid(T));
    if (it==table.end()) return;
    for(auto&&f:it->second)
      f(t);
  }
};

像上面這樣的東西應該工作。 類型T必須完全匹配。 參考不受支持。 代碼未編譯,設計合理,可能有拼寫錯誤。

這不會被重構為原始類型。 你應該明確地傳遞T ,不要依賴扣除,因為它是脆弱的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM