我一直致力于设计图书馆。其中一个方面是EventManager
。
到目前为止,设计是这样的:
Client client
client.on(string, function);
其中字符串为std::string
且函数为std::function<void()>
client.on
定义如下:
void Client::on(const std::string& name, const std::function<void()>& function) {
_eventManager->add(string, function);
}
而_eventManager->add(string, function)
唯一的目标是创建一个名为Event
的结构,并在其中存储名称和函数,然后将新的支柱推送到矢量。
现在我可以做类似的事情:
_eventManager->emit("test");
然后它将循环向量数组并找到任何event.name
,它等于您在调用emit
时使用的名称并在该结构中运行该函数。
这一切都非常棒,而且非常棒,但是它并不是我所需要的,也不会起作用,因为我需要用_eventManager->emit()
发送第二个参数。第二个参数是未知的,也不是未知的,但它可以是基于您在第一个参数中输入的字符串的多数据类型。
使用示例:
Client client();
client.on("ready", [](User user) {
user.test();
});
User user;
_eventManager->emit("ready", user); //I know this does not exists but it is nearly an example.
client.on("message_created", [](Message message) {
std::cout << message << std::endl; //Operator overload here
}
Message message("Something to print");
_eventManager->emit("message_created", message));
我考虑过使用boost::variant
来允许传递多个类型,但是你必须通过在函数中做这样的事情来检索它们。
client.on("ready", [](boost::variant<User, Message> args){
User user = boost::get<User>(args);
});
并且假设它也很简单,我宁愿不让使用库的人强制在所有事件中使用boost::get
来检索传递的类。
据说,上述所有精彩信息,我想做什么的另一种选择是什么?关于为什么我应该或不应该做我正在做的事情的任何建议?
这花了我很长时间才写出来,所以先谢谢你,我希望所有这一切都有意义。
答案 0 :(得分:2)
我有一个使用变量模板的解决方案(C ++ 14),但它看起来像一个可怕的黑客。它的一个缺点是变量模板只能是静态的。假设你可以忍受它(虽然它已经很糟糕了)...
对于每种类型的消息(此处为type =传递给处理程序的参数列表),您将拥有一个单独的处理程序列表。这可以这样实现:
template<typename F> static map<string, vector<F>> list;
此处F
的示例是void(int)
- 一个接收一个int
参数的函数。另一个例子是void(int, int)
- 一个接收两个int
参数的函数。我在这里使用的数据结构为每个消息名称存储vector
个处理程序。我也可以使用multimap
。
当&#34;注册&#34;一个事件处理程序,只需将其添加到处理程序列表中:
template<typename F> static void add_handler(string s, F f)
{
list<F>[s].push_back(f);
}
查找事件处理程序时,应明确指定其类型。这是实现类型安全的关键部分 - 它只会在与被调用者的类型相对应的数据结构中查找。
template<typename F, typename... A> static void call_handlers(string s, A... args)
{
for (F f: list<F>[s])
f(args...);
}
用法:
// Define event handlers
// Their type SHOULD be explicit (not lambda), because we will reference it further
function<void(int)> action1 = [](int k){cout << "notify user " << k << '\n';};
function<void(int)> action2 = [](int k){cout << "alert user " << k << '\n';};
function<void(int, int)> action3 = [](int a, int b){cout << "give $" << a << " to user " << b << '\n';};
// Register the handlers
add_handler("good_event", action1);
add_handler("good_event", action2);
add_handler("bad_event", action2);
add_handler("money_event", action3);
// Generate events, which will call the handlers
call_handlers<function<void(int)>>("good_event", 7);
call_handlers<function<void(int)>>("bad_event", 8);
call_handlers<function<void(int, int)>>("money_event", 100, 9);
// Wrong call, but no compilation error - the handler is just not found
call_handlers<function<void(int)>>("money_event", 99);