我只是尝试为给定的std::packaged_task
创建std::bind
。
#include <functional>
#include <future>
class A
{
public:
template<class T>
void execute(T func)
{
std::packaged_task<T> task(func);
}
};
int main()
{
auto func = std::bind([](int x) { return x*x; }, 5);
A name;
name.execute(func);
}
main.cpp:实例化'void A :: execute(T)[with T = std :: _ Bind(int)&gt;]':main.cpp:20:20:必需 从这里main.cpp:10:36:错误: “的std :: packaged_task(INT)&GT; &GT;任务'有 不完全类型 std :: packaged_task task(func);
我正在使用G ++ 5.2.0和C ++ 14。
有人有想法吗?
谢谢,
答案 0 :(得分:3)
从c ++ 11开始,不可能将函数参数声明为auto(我相信它是c ++ 17的一部分)。不幸的是我没有支持该功能的编译器,我不太确定它的语义,但解决方法是使用模板:
#include <future>
#include <functional>
template<class T>
void execute(std::function<T> func) // is a std::bind
{
std::packaged_task<T> task(func);
//...
}
你可以这样使用:
std::function<int()> func = std::bind([](int x) { return x*x; }, 5);
execute(func);
出现此错误的原因是std::packaged_task
仅适用于ReturnType(Args...)
形式的模板参数。因此,如果您传递的内容与std::_Binder
或std::bind
返回的std::function
不同,则会显示为未定义。
修改强>
关于推断std :: function类型的评论:
您可以使用lambdas而不是std::bind()
。
如果你的评论中有一个A
课程,其功能为doSomething(int x)
:
class A
{
public:
int doSomething(int x)
{
return x *x;
}
};
我们需要将执行功能更改为以下内容(请参阅Yakk的回答):
template<class F, class...Args>
void execute(F&& func, Args&&...args)
{
using zF = std::decay_t<F>&&;
using R = std::result_of_t< zF(Args...) >;
std::packaged_task<R()> task(
std::bind([func = std::forward<F>(func)](auto&&...args)mutable->R{
return std::move(func)(decltype(args)(args)...);
}, std::forward<Args>(args)...)
);
}
现在你可以像这样使用它:
A a;
auto f = [](A& inst, int x) { return inst.doSomething(x); };
execute(f, a, 5);
// or
auto g = [&]() { return a.doSomething(5); };
execute(g);
注意
请注意a
的生命周期,因为packaged_task可以异步运行。
答案 1 :(得分:1)
这是一个简单的解决方案:
template<class...Args, class F>
void execute(F&& func)
{
using R = std::result_of_t< std::decay_t<F>(Args...) >;
std::packaged_task<R(Args...)> task(std::forward<F>(func));
}
我添加了完美转发,以及传递参数的选项。如果你没有传入参数,它假定传入的callable接受0个参数。
使用示例:
auto func = std::bind([](int x) { return x*x; }, 5);
A name;
name.execute(func);
如果func
需要参数,则必须明确传递它们。这是公平的,因为在不知道它会期望什么参数的情况下很难使用std::packaged_task
。 ;)
这也编译:
auto func = [](int x) { return x*x; };
A name;
name.execute<int>(func);
但是你打算如何使用这个打包的任务很棘手。
如果您想模仿std::async
之类的界面,我们可以这样做:
template<class F, class...Args>
void execute(F&& func, Args&&...args)
{
using zF = std::decay_t<F>&&;
using R = std::result_of_t< zF(Args...) >;
std::packaged_task<R()> task(
std::bind( [func=std::forward<F>(func)](auto&&...args)mutable->R{
return std::move(func)(decltype(args)(args)...);
}, std::forward<Args>(args)... )
);
}
小心地将传递的func
包装在lambda中,以避免在bind
上调用bind
,然后绑定传入的参数。
现在你可以:
name.execute([](int x){ return x*x; }, 5);
根本不使用bind
。
上面的代码尚未编译,可能包含tpyos。