具有不同参数的std :: function的集合 [英] Collection of std::functions with different arguments

查看:126
本文介绍了具有不同参数的std :: function的集合的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试编写一个简单的调度程序,用户代码可以将回调附加到该调度程序上。
每个事件都有一个已知的签名,用户代码将需要使用正确的数字和参数类型来调用dispatch。这由可变参数来管理。但是,不接受freestandingInt,因为矢量的类型不正确。

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. This is managed by the variadic arguments. But, freestandingInt is not accepted, as the vector is not of the right type. How to make it generic?

遵循一个最小的示例

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);

}


推荐答案

一种基于将 std :: multimap 从函数的 std :: type_index 制作为<$ c的方法适当类型的$ c> std :: function :

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:

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

输出:

freestandingInt 5

这篇关于具有不同参数的std :: function的集合的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆