7

簡単なディスパッチャーを作成しようとしています。ユーザー コードはそれにコールバックをアタッチできます。各イベントには既知のシグネチャがあり、ユーザー コードは正しい番号と引数の型でディスパッチを呼び出す必要があります。これは可変引数によって管理されます。ただし、ベクトルが正しいタイプではないため、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);

}
4

2 に答える 2

8

関数の から をstd::multimap適切な型の にすることに基づくアプローチを次に示します。std::type_indexstd::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
于 2013-06-02T15:28:42.530 に答える