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

标签 c++

我一直致力于设计图书馆。其中一个方面将是 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 的结构并将名称和功能存储在其中,然后将新的支柱推送到 vector 。

现在我可以做类似的事情: _eventManager->emit("test"); 然后它将循环 vector 数组并找到任何 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在所有事件中检索通过的类。

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

这花了我很长时间才写出来,所以先谢谢你,我希望所有这些都有意义。

最佳答案

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

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

template<typename F> static map<string, vector<F>> list;

此处 F 的示例是 void(int) - 一个接收一个 int 参数的函数。另一个例子是 void(int, int) - 一个接收两个 int 参数的函数。我在这里使用的数据结构为每个消息名称存储一个处理程序的 vector。我也可以使用 multimap

“注册”事件处理程序时,只需将其添加到处理程序列表中即可:

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

关于C++ 设计事件处理程序类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44372512/

相关文章:

c++ - 关于Linux的二进制兼容性

java - 拼出时间

c++ - 如何为ffplay写一个接口(interface),让它对键盘事件使用react

iphone - 将 C++ 代码重写为 Objective C

C++ - 通过指针表示所有权

c++ - 具有固定插入次数的 Map 的内存分配

c++ - 默认情况下,引用和指针是否始终代表 0 索引? C++

c++ - Netbeans 中的错误 "Unable to resolve identifier"

c++ - 如何将年龄读成双倍

c++ - OpenGL:glDrawArrays 有效但 glDrawElements 无效