我试图从头开始实现 我发现了什么似乎是一个解决方案,通过使用 (最坏的情况,我想知道我必须自己重新实现多少 我的问题是: 我如何使我的代码工作,不使用 是我的 在c++ 1z中支持参数包捕获的讨论和/或建议将被感激地接受。 下面是我的代码:std::async
,并且遇到了仅移动类型参数的问题。它的要点是,c++ 14的初始捕获允许我们"通过移动"或"通过完全转发"捕获单个变量,但是它们似乎不允许我们"通过移动"或"通过完全转发"捕获参数包,因为你不能通过初始捕获捕获参数包,只能通过命名捕获。std::bind
捕获参数包"移动",然后使用包装器将参数从绑定对象的存储中移动到我真正想要调用的函数的参数槽中。如果你不去想太多,它甚至看起来很优雅。但我禁不住想,一定有更好的办法——理想的办法是完全不依赖于std::bind
。std::bind
才能摆脱它。这个练习的部分目的是展示事情是如何实现的,所以有一个像std::bind
这样复杂的依赖真的很糟糕。std::bind
?(即,只使用核心语言特性。std::bind
变通防弹吗?也就是说,有没有人可以展示一个例子,其中STL的std::async
工作和我的Async
失败?template<typename UniqueFunctionVoidVoid>
auto FireAndForget(UniqueFunctionVoidVoid&& uf)
{
std::thread(std::forward<UniqueFunctionVoidVoid>(uf)).detach();
}
template<typename Func, typename... Args>
auto Async(Func func, Args... args)
-> std::future<decltype(func(std::move(args)...))>
{
using R = decltype(func(std::move(args)...));
std::packaged_task<R(Args...)> task(std::move(func));
std::future<R> result = task.get_future();
#ifdef FAIL
// sadly this syntax is not supported
auto bound = [task = std::move(task), args = std::move(args)...]() { task(std::move(args)...) };
#else
// this appears to work
auto wrapper = [](std::packaged_task<R(Args...)>& task, Args&... args) { task(std::move(args)...); };
auto bound = std::bind(wrapper, std::move(task), std::move(args)...);
#endif
FireAndForget(std::move(bound));
return result;
}
int main()
{
auto f3 = [x = std::unique_ptr<int>{}](std::unique_ptr<int> y) -> bool { sleep(2); return x == y; };
std::future<bool> r3 = Async(std::move(f3), std::unique_ptr<int>{});
std::future<bool> r4 = Async(std::move(f3), std::unique_ptr<int>(new int));
assert(r3.get() == true);
assert(r4.get() == false);
}
有人离线向我建议,另一种方法是在std::tuple
中捕获args
包,然后使用类似std::experimental::apply
的东西将该元组重新扩展到task
的参数列表中(即将在您附近的c++ 17标准库中出现!)。
auto bound = [task = std::move(task), args = std::make_tuple(std::move(args)...)]() {
std::experimental::apply(task, args);
};
这样更干净。我们减少了库代码的数量,从bind
减少到"仅仅"tuple
。但这仍然是一个很大的依赖,我希望能够摆脱!