我试图在C ++ Concurrency in Action(第2版)中修改Anthony William的代码并遇到一些错误。详情如下:
这是Anthony Williams的原始代码:
template<typename Func>
std::experimental::future<decltype(std::declval<Func>()())> spawn_async(Func&& func){
std::experimental::promise<decltype(std::declval<Func>()())> p;
auto res=p.get_future();
std::thread t(
[p=std::move(p),f=std::decay_t<Func>(func)]() mutable{
try{
p.set_value_at_thread_exit(f());
} catch(...){
p.set_exception_at_thread_exit(std::current_exception());
}
});
t.detach();
return res;
}
我想修改上面的代码,以便spawn_async可以接受任何可调用的,而不仅仅是那些带有空参数列表的调用。
这是我的代码:
spawn_async.hpp
#include <future>
#include <thread>
#include <functional>
#include <type_traits>
template<typename Func, typename... Args>
auto spawn_async(Func&& func, Args&&... args)
{
std::promise<std::result_of_t<Func(Args&&...)>> prom;
auto res = prom.get_future();
auto lambda = [p = std::move(prom), f=std::decay_t<Func>(func)](auto&&... a) mutable
{
try
{
p.set_value_at_thread_exit(f(a...));
}
catch (...)
{
p.set_exception_at_thread_exit(std::current_exception());
}
};
auto async_func = std::bind(lambda, std::forward<Args>(args)...);
std::thread t(async_func);
t.detach();
return res;
}
我已使用std::experimental::future
和std::experimental::promise
替换了安东尼代码中的std::future
和std::promise
。
这是我用来测试它的代码:
TEST.CPP
#include <iostream>
#include "spawn_async.hpp"
int func(int a, double d)
{
return 42;
}
int main()
{
auto ret = spawn_async(func, 1, 2.4);
std::cout << ret.get() << std::endl;
}
我使用g ++(7.2.1)得到以下错误:
g++ --std=c++17 test.cpp spawn_async.hpp
In file included from spawn_async.hpp:3:0,
from test.cpp:2:
/usr/include/c++/7/functional: In instantiation of ‘std::_Bind<_Functor(_Bound_args ...)>::_Bind(const _Functor&, _Args&& ...) [with _Args = {int, double}; _Functor = spawn_async(Func&&, Args&& ...) [with Func = int (&)(int, double); Args = {int, double}; typename std::result_of<Func(Args&& ...)>::type = int]::<lambda(auto:1&& ...)>; _Bound_args = {int, double}]’:
/usr/include/c++/7/functional:878:38: required from ‘typename std::_Bind_helper<std::__is_socketlike<_Func>::value, _Func, _BoundArgs ...>::type std::bind(_Func&&, _BoundArgs&& ...) [with _Func = spawn_async(Func&&, Args&& ...) [with Func = int (&)(int, double); Args = {int, double}; typename std::result_of<Func(Args&& ...)>::type = int]::<lambda(auto:1&& ...)>&; _BoundArgs = {int, double}; typename std::_Bind_helper<std::__is_socketlike<_Func>::value, _Func, _BoundArgs ...>::type = std::_Bind<spawn_async(Func&&, Args&& ...) [with Func = int (&)(int, double); Args = {int, double}; typename std::result_of<Func(Args&& ...)>::type = int]::<lambda(auto:1&& ...)>(int, double)>]’
spawn_async.hpp:23:29: required from ‘std::future<typename std::result_of<Func(Args&& ...)>::type> spawn_async(Func&&, Args&& ...) [with Func = int (&)(int, double); Args = {int, double}; typename std::result_of<Func(Args&& ...)>::type = int]’
test.cpp:11:37: required from here
/usr/include/c++/7/functional:529:59: **error: use of deleted function ‘spawn_async(Func&&, Args&& ...) [with Func = int (&)(int, double); Args = {int, double}; typename std::result_of<Func(Args&& ...)>::type = int]::<lambda(auto:1&& ...)>::<lambda>(const spawn_async(Func&&, Args&& ...) [with Func = int (&)(int, double); Args = {int, double}; typename std::result_of<Func(Args&& ...)>::type = int]::<lambda(auto:1&& ...)>&)’
: _M_f(__f), _M_bound_args(std::forward<_Args>(__args)...)**
^
In file included from test.cpp:2:0:
spawn_async.hpp:12:64: **note: ‘spawn_async(Func&&, Args&& ...) [with Func = int (&)(int, double); Args = {int, double}; typename std::result_of<Func(Args&& ...)>::type = int]::<lambda(auto:1&& ...)>::<lambda>(const spawn_async(Func&&, Args&& ...) [with Func = int (&)(int, double); Args = {int, double}; typename std::result_of<Func(Args&& ...)>::type = int]::<lambda(auto:1&& ...)>&)’ is implicitly deleted because the default definition would be ill-formed:**
**auto lambda = [p = std::move(prom), f=std::decay_t<Func>(func)](auto&&... a) mutable**
^
spawn_async.hpp:12:64: error: use of deleted function ‘std::promise<_Res>::promise(const std::promise<_Res>&) [with _Res = int]’
In file included from spawn_async.hpp:1:0,
from test.cpp:2:
/usr/include/c++/7/future:1077:7: note: declared here
**promise(const promise&) = delete;**
^~~~~~~
(etc etc etc)
我不明白为什么编译器报告spawn_async函数被隐式删除,因为它正是我试图实例化的函数。
它还说我试图使用std :: promise类的已删除的复制构造函数,但在我的代码中,我在使用C ++ 14 lambda init捕获功能时调用了移动构造函数。
我不明白为什么我会收到这些错误以及如何修改我的代码以使其行为正确。任何指针或帮助将不胜感激。感谢。
答案 0 :(得分:5)
我不明白为什么编译器报告spawn_async函数被隐式删除,因为它正是我试图实例化的函数。
未删除spawn_async,std :: promise copy costructor is(如错误所示)。问题出在
行auto async_func = std::bind(lambda, std::forward<Args>(args)...);
std::thread t(async_func);
std::bind会将lambda复制到那里;此外,只有当lambda及其绑定参数都是(*)时,bind才会返回复制可构造对象。在这种情况下,lambda仅由于其promise成员而是可移动的。相反,它应该是
std::thread t( std::bind( std::move(lambda), std::forward<Args>(args)...)
);
或只是
std::thread t( std::move(lambda), std::forward<Args>(args)... );
让线程自己进行绑定(它会像bind一样进行decay-copy但没有添加std :: bind开销)
(*)更确切地说,bind保存通过完美转发构造的decay_t&#f;类型的成员