简体   繁体   English

std ::具有不同参数的函数的集合

[英]Collection of std::functions with different arguments

I am trying to write a simple dispatcher, the user code can attach callbacks to it. 我正在尝试编写一个简单的调度程序,用户代码可以将回调附加到它。 Each event has a known signature, and the user code will need to call dispatch with the right number and argument types. 每个事件都有一个已知的签名,用户代码需要使用正确的数字和参数类型调用dispatch。 This is managed by the variadic arguments. 这由可变参数管理。 But, freestandingInt is not accepted, as the vector is not of the right type. 但是,freestandingInt不被接受,因为向量不是正确的类型。 How to make it generic? 如何使它通用?

Follows a minimal example 遵循一个最小的例子

void freestanding() {
 std::cout << "freestanding" << std::endl;
}

void freestandingInt(int iArg) {
  std::cout << "freestandingInt " << iArg << std::endl;
}


struct Dispatcher {
 typedef struct Event_ {
   std::vector<std::function<void()> > listeners;
 } Event;

 template<class... Args>
 void dispatch(int eventNr, Args&&... args) {
   for (auto listener: events[eventNr].listeners) {
     std::function<void()> f(std::bind(listener, std::forward<Args>(args)...));
     f();
   }
 }

 std::map<int, Event> events;
};

int main (int argc, char **argv) {
  Dispatcher disp;
  disp.events[0].listeners.push_back(freestanding);
  disp.dispatch(0); // OK

  // error here
  //disp.events[1].listeners.push_back(freestandingInt);

}

Here is an approach based on making a std::multimap from the std::type_index of the function to a std::function of the appropriate type: 这是一种基于将std::multimap从函数的std::type_index为适当类型的std::function的方法:

#include <functional>
#include <iostream>
#include <map>
#include <memory>
#include <typeindex>

void freestanding() {
  std::cout << "freestanding" << std::endl;
}

void freestandingInt(int iArg) {
  std::cout << "freestandingInt " << iArg << std::endl;
}

// Base class for all functions so that we can store all functions
// in a single container.
struct Function {
  virtual ~Function() { }
};

// Derived class template for functions with a particular signature.
template <typename T>
struct BasicFunction : Function {
  std::function<T> function;
  BasicFunction(std::function<T> function) : function(function) { }
};

// Generic container of listeners for any type of function
typedef std::multimap<std::type_index,std::unique_ptr<Function> > Listeners;

template <typename Func>
static void addListener(Listeners &listeners,Func &function)
{
  std::type_index index(typeid(Func));
  std::unique_ptr<Function>
    func_ptr(new BasicFunction<Func>(std::function<Func>(function)));
  listeners.insert(Listeners::value_type(index,std::move(func_ptr)));
}

template <typename... Args>
static void callListeners(const Listeners &listeners,Args&&... args)
{
  typedef void Func(typename std::remove_reference<Args>::type...);
  std::type_index index(typeid(Func));
  Listeners::const_iterator i = listeners.lower_bound(index);
  Listeners::const_iterator j = listeners.upper_bound(index);
  for (;i!=j; ++i) {
    const Function &f = *i->second;
    std::function<Func> func =
      static_cast<const BasicFunction<Func> &>(f).function;
    func(std::forward<Args>(args)...);
  }
}

struct Dispatcher {
  typedef struct Event_ {
    Listeners listeners;
  } Event;

  template<class... Args>
  void dispatch(int eventNr, Args&&... args) {
    callListeners(events[eventNr].listeners,std::forward<Args>(args)...);
  }

  std::map<int, Event> events;
};

int main (int argc, char **argv) {
  Dispatcher disp;
  addListener(disp.events[0].listeners,freestanding);
  addListener(disp.events[0].listeners,freestandingInt);
  disp.dispatch(0,5);
}

Output: 输出:

freestandingInt 5

Additional approach is using std::bind 其他方法是使用std :: bind

void show_text(const string& t)
{
    cout << "TEXT: " << t << endl;
}

std::function <void ()> f = std::bind(show_text, "Bound function"); 
    /*notice that the signature of the std::function f is void() */

more on that in this amazing post: https://oopscenities.net/2012/02/24/c11-stdfunction-and-stdbind/ 更多关于这个惊人的帖子: https//oopscenities.net/2012/02/24/c11-stdfunction-and-stdbind/

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM