我正在尝试编写一个简单的调度程序,用户代码可以附加回调函数。 每个事件都有一个已知的签名,用户代码需要使用正确的数字和参数类型调用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);
}
答案 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/