C++ 在F&;之后添加另一个函数作为参数&;,Args&&;。。。模板函数C++;

C++ 在F&;之后添加另一个函数作为参数&;,Args&&;。。。模板函数C++;,c++,c++11,templates,variadic-templates,C++,C++11,Templates,Variadic Templates,我正在为我的EventLoop类编写一个异步成员函数,它将把繁重的计算任务发布到一个全局线程池,然后获取该任务的结果,并将一个finish回调函数排队,该函数将前面工作的结果作为参数返回给EventLoop,让EventLoop处理(调用)稍后将返回finish回调 因此,通常异步成员函数应该使用两个函数作为参数,第一个函数被设计为任何返回类型的任务函数,第二个函数是一个finish回调函数,它将第一个函数的返回值作为参数 我的第一次尝试代码如下: class EventLoop { publ

我正在为我的EventLoop类编写一个异步成员函数,它将把繁重的计算任务发布到一个全局线程池,然后获取该任务的结果,并将一个finish回调函数排队,该函数将前面工作的结果作为参数返回给EventLoop,让EventLoop处理(调用)稍后将返回finish回调

因此,通常异步成员函数应该使用两个函数作为参数,第一个函数被设计为任何返回类型的任务函数,第二个函数是一个finish回调函数,它将第一个函数的返回值作为参数

我的第一次尝试代码如下:

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();
        });
    });
}
class事件循环
{
公众:
使用DeferCallback=std::函数;
//另一个线程调用将工作排入eventloop队列
无效队列工作(cb);
模板
void async(F&&task\u func、Args&&Args、std::function&&finish\u cb){
g_threadpool::get_instance()->post([this,task_func,args…,finish_cb](){
使用task\u ret\u t=std::invoke\u result\t;
task_ret_t res=task_func(args…);
这->队列工作([finish\u cb,&res](){
完成cb(res);
});
});
}
//对于无效返回类型的任务函数
模板
void async(F&&task\u func、Args&&Args、std::function&&finish\u cb){
g_threadpool::get_instance()->post([this,task_func,args…,finish_cb](){
任务函数(参数…);
此->队列工作([finish\u cb](){
完成_cb();
});
});
}
我测试并发现它只在我没有将任何内容传递给…args或编译器无法正常工作时才起作用。然后我进行了一些搜索并发现以下问题: 它基本上告诉我:

[…]如果主类模板或别名>模板的模板参数是模板参数包,则应为最后一个模板->参数。[…]

如果我必须显式地实例化异步函数,它将很难使用

然后我试试这个:

template<typename Ret,typename ...Args>
void async(std::function<Ret(Args...)> &&task_func,std::function<void(Ret&)> &&finish_cb){ ... }
模板
void异步(std::function&&task\u func,std::function&&finish\u cb){…}
发现除了std::function之外,我无法将lambda函数或member函数传递给第一个参数,这是不理想的。相关问题:

有什么办法可以解决这个问题吗

如果我必须显式地实例化异步函数,它将很难使用

在你的情况下,这特别困难,因为

template <typename F, typename ... Args>
void async (F &&task_func,
            Args && ...args,
            std::function<void(std::invoke_result_t<F,Args...>&)> &&finish_cb)
如果您的问题是需要两个版本的
async()
,一个是
F1
返回
void
(不返回值),另一个是
F1
返回值,您可以将
std::invoke\u result\t
与SFINAE一起使用

// void (no res) version
template <typename F1, typename F2, typename ...Args>
std::enable_if_t<true == std::is_same_v<void, std::invoke_result_t<F,Args...>>>
      async (F1 && task_func, F2 && finish_cb, Args && ... args)
 { /* do something */ }

// non-void (with res) version
template <typename F1, typename F2, typename ...Args>
std::enable_if_t<false == std::is_same_v<void, std::invoke_result_t<F,Args...>>>
      async (F1 && task_func, F2 && finish_cb, Args && ... args)
 { /* do something */ }
//无效(无恢复)版本
模板
std::如果启用,则启用
异步(F1&&task\u func、F2&&finish\u cb、Args&&…Args)
{/*做点什么*/}
//非无效(带res)版本
模板
std::如果启用,则启用
异步(F1&&task\u func、F2&&finish\u cb、Args&&…Args)
{/*做点什么*/}

感谢您的建议,这是一个可接受的选项,将invoke\u result\t与SFINAE结合使用更为优雅
// void (no res) version
template <typename F1, typename F2, typename ...Args>
std::enable_if_t<true == std::is_same_v<void, std::invoke_result_t<F,Args...>>>
      async (F1 && task_func, F2 && finish_cb, Args && ... args)
 { /* do something */ }

// non-void (with res) version
template <typename F1, typename F2, typename ...Args>
std::enable_if_t<false == std::is_same_v<void, std::invoke_result_t<F,Args...>>>
      async (F1 && task_func, F2 && finish_cb, Args && ... args)
 { /* do something */ }