C++版本是11
我的需求是这样的:
我需要实现一个注册事件回调函数的方法,模型如下:
Server::on(std::string event_name, callback handler)
{
}
其中,callback
的参数和event_name
有关。例如:
int (*onReceive)(Server *, EventData *);
void (*onStart)(Server *serv);
也就是说,我需要用一种callback
来表达出以下两种参数的回调函数:
(Server *, EventData *)
(Server *serv)
请问这个可以通过std::function
实现吗?或者说有其他的方法实现?
举一个具体的例子,我知道代码会有问题,但是可以更加清晰的表达我的想法:
#include <iostream>
#include <cstdlib>
#include <functional>
#include <vector>
class server
{
public:
template <class... Args>
std::vector<std::string, std::function<void(Args... args)>> callbacks;
template <class... Args>
void on(std::string event_name, std::function<void(server *serv, Args... args)> fn)
{
callbacks[event_name] = fn;
}
void event_loop(Event event)
{
if (event == "start")
{
callbacks[event_name](this);
}
if (event == "receive")
{
callbacks[event_name](this, data);
}
}
};
int main(int argc, char const *argv[])
{
server serv;
serv.on("Start", [](server *serv)
{
std::cout << "server start..." << std::endl;
});
serv.on("Receive", [](server *serv, EventData *data)
{
// 读取客户端发来的数据,处理业务逻辑
});
serv.start(); // 启动服务器
return 0;
}
std::function
无法表达任意可调用对象。如果你需要从callback调用,那么要让一组可调用对象构成重载。
如果不需要从callback调用,那么用类似
std::variant
或boost::variant
的容器作为形式参数,然后根据事件类型来赋值。伪代码中的问题:
以下三点对你的伪代码都有不同程度的假设,没有详尽分析可能性。
server::on
时,实际参数如果是lambda expression,就得提供模板参数(因为你这样写无法推导),即serv.on<EventData *>("Receive", [](server *serv, EventData *data) {});
。如果你想要一个可以推导的写法,那么需要用到类似callable_trait
的萃取,这个标准库是没有的。event_loop
里指明了调用时所有可能的参数表,这些参数表必须提供给callbacks
。否则server
本身得是一个模板才行。callbacks
得是一个异质关联容器,你写的是变量模板声明。boost的c++11下模板元编程库mp11提供了这种容器。如果以
callbacks
的声明为重点,那么你思路的技术难点是异质关联容器的访问和修改。你需要熟练掌握这种容器在C++11下的用法。标准库没有提供这方面的支持,最终也不是写一个server
类能够完成的。如果以调用
callbacks[event_name](this);
为重点,那么抽象类会是一个很好的解决方案,或者用variant
。其余部分都会展开太多可能性。