I'm writing a async member function for my EventLoop class, which would posts the heavy computational task to a global thread pool, and then gets the result of that task and queues a finish callback function that takes the result of the previous work as a parameter back to the EventLoop to let the eventloop handle(call) the finish callback later.
So generally the async member function should takes two functions as the parameter, the first one is designed to be a task function of any return type, the second one is a finish callback that takes the return value of the first function as a parameter.
My first attempt code is as follows:
class EventLoop
{
public:
using DeferCallback=std::function<void()>;
//call by another thread to queue work into the eventloop
void queue_work(DeferCallback cb);
template<typename F,typename ...Args>
void async(F &&task_func,Args&& ...args,std::function<void(std::invoke_result_t<F,Args...>&)> &&finish_cb){
g_threadpool::get_instance()->post([this,task_func,args...,finish_cb](){
using task_ret_t=std::invoke_result_t<F,Args...>;
task_ret_t res=task_func(args...);
this->queue_work([finish_cb,&res](){
finish_cb(res);
});
});
}
//for task func of void return type
template<typename F,typename ...Args>
void async(F &&task_func,Args&& ...args,std::function<void(void)> &&finish_cb){
g_threadpool::get_instance()->post([this,task_func,args...,finish_cb](){
task_func(args...);
this->queue_work([finish_cb](){
finish_cb();
});
});
}
I tested and found that it only works when I don't pass anything to ...args, or the compiler couldn't work correctly. Then I do some search and find the following question: Parameter pack must be at the end of the parameter list... When and why? It basically tells me:
[...]If a template-parameter of a primary class template or alias >template is a template parameter pack, it shall be the last template->parameter.[...]
And if I have to explicitly instantiate the async function it will be hard to use.
Then I try this:
template<typename Ret,typename ...Args>
void async(std::function<Ret(Args...)> &&task_func,std::function<void(Ret&)> &&finish_cb){ ... }
and find out that I can't pass lambda function or member function except a std::function to the first parameter, which is not ideal. related question:Deduce template argument from std::function call signature
So is there any way to work around?
Aucun commentaire:
Enregistrer un commentaire