模板函数被定义为已删除

MS *_*nth 1 c++ templates variadic-templates c++14

我试图在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;
}
Run Code Online (Sandbox Code Playgroud)

我想修改上面的代码,以便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;                     
}
Run Code Online (Sandbox Code Playgroud)

我已经更换std::experimental::future,并std::experimental::promise在安东尼的代码std::futurestd::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;
}
Run Code Online (Sandbox Code Playgroud)

我用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)
Run Code Online (Sandbox Code Playgroud)

我不明白为什么编译器报告spawn_async函数被隐式删除,因为它正是我试图实例化的函数.

它还说我试图使用std :: promise类的已删除的复制构造函数,但在我的代码中,我在使用C++ 14 lambda init捕获功能时调用了移动构造函数.

我不明白为什么我会收到这些错误以及如何修改我的代码以使其行为正确.任何指针或帮助将不胜感激.谢谢.

Mas*_*nes 5

我不明白为什么编译器报告spawn_async函数被隐式删除,因为它正是我试图实例化的函数.

不删除spawn_async,std :: promise copy costructor是(如错误所示).问题在于这些问题

auto async_func = std::bind(lambda, std::forward<Args>(args)...);
std::thread t(async_func);
Run Code Online (Sandbox Code Playgroud)

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)... );
Run Code Online (Sandbox Code Playgroud)

并让线程自己进行绑定(它将像bind一样进行decay-copy但没有添加std :: bind开销)

(*)更准确地说,bind通过完美转发来保存decay_t'ed类型的成员