Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/161.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ C++;设计事件处理程序类_C++ - Fatal编程技术网

C++ C++;设计事件处理程序类

C++ C++;设计事件处理程序类,c++,C++,我一直在设计一个图书馆。其中一个方面是EventManager 到目前为止,设计是这样的: Client client client.on(string, function); template<typename F> static map<string, vector<F>> list; 其中字符串是std::string,函数是std::function client.on的定义如下: void Client::on(const std::string

我一直在设计一个图书馆。其中一个方面是
EventManager

到目前为止,设计是这样的:

Client client
client.on(string, function);
template<typename F> static map<string, vector<F>> list;
其中字符串是
std::string
,函数是
std::function
client.on
的定义如下:

void Client::on(const std::string& name, const std::function<void()>& function) {
    _eventManager->add(string, function);
}
我考虑使用
boost::variant
来允许传递多个类型,但是您必须通过在函数中执行类似操作来检索它们

client.on("ready", [](boost::variant<User, Message> args){
    User user = boost::get<User>(args);
}); 
client.on(“ready”,[](boost::variant args){
User=boost::get(args);
}); 
假设它也很简单,我不希望使用库的人在所有事件中强制使用
boost::get
,以检索通过的类

也就是说,有了上面所有精彩的信息,我想做的另一个选择是什么?关于我为什么应该或不应该做我正在做的事情,有什么建议吗


这篇文章花了我很长时间才写成,所以我希望所有这些都有意义。

我有一个使用变量模板(C++14)的解决方案,但它看起来像一个可怕的黑客。它的一个缺点是变量模板只能是静态的。假设你能忍受它(尽管它已经很糟糕了)

对于每种类型的消息(此处type=传递给处理程序的参数列表),您将有一个单独的处理程序列表。这可以这样实现:

Client client
client.on(string, function);
template<typename F> static map<string, vector<F>> list;
查找事件处理程序时,应显式指定其类型。这是实现类型安全的一个关键部分——它将只在与被调用处理程序的类型对应的数据结构中查找

template<typename F, typename... A> static void call_handlers(string s, A... args)
{
    for (F f: list<F>[s])
        f(args...);
}
模板静态无效调用\u处理程序(字符串s、A…args)
{
对于(F:list[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);
//定义事件处理程序
//它们的类型应该是显式的(而不是lambda),因为我们将进一步引用它

函数action1=[](int k){为什么不直接使用现有的库,比如,或类似的库?为什么要经历重新发明轮子的痛苦?你的
函数模板知道回调接受的参数类型。它可以实例化一个中间thunk,它接受一个变量,提取期望的类型,并且(如果成功)调用原始回调函数。