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

时间:2013-06-02 14:42:46

标签: c++ c++11 variadic-templates std-function

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

遵循最小的例子

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

}

2 个答案:

答案 0 :(得分:7)

以下是一种方法,该方法基于将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);
}

输出:

freestandingInt 5

答案 1 :(得分:0)

其他方法是使用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() */

更多关于这个惊人的帖子:https://oopscenities.net/2012/02/24/c11-stdfunction-and-stdbind/