2013-06-03 57 views
7

我試圖移動std::packaged_taskstd::function<void()>一個std::vector,因爲std::packaged_task已經void operator()(ArgTypes... args)超載,它應該是可轉換到std::function<void()>,是嗎?的std ::功能和std :: packaged_task轉換

這不會編譯MSVC和鏗鏘,MSVC抱怨不能將void轉換爲int,鏗鏘抱怨刪除拷貝構造函數爲std::packaged_task,應該不會移動版本std::vector::push_back被調用?發生了什麼,這是一個錯誤?

int main() 
{ 
    std::vector<std::function<void()>> vec; 
    std::packaged_task<int()> task([] { return 100; }); 
    vec.push_back(std::move(task)); 
} 

這裏是鐺

In file included from main.cpp:1: 
In file included from /usr/bin/../lib/c++/v1/iostream:38: 
In file included from /usr/bin/../lib/c++/v1/ios:216: 
In file included from /usr/bin/../lib/c++/v1/__locale:15: 
In file included from /usr/bin/../lib/c++/v1/string:434: 
In file included from /usr/bin/../lib/c++/v1/algorithm:594: 
/usr/bin/../lib/c++/v1/memory:2236:15: error: call to deleted constructor of 
     'std::__1::packaged_task<int()>' 
       __first_(_VSTD::forward<_Args1>(get<_I1>(__first_args))...) 
      ^  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
/usr/bin/../lib/c++/v1/memory:2414:15: note: in instantiation of function 
     template specialization 
     'std::__1::__libcpp_compressed_pair_imp<std::__1::packaged_task<int()>, 
     std::__1::allocator<std::__1::packaged_task<int()> >, 
     2>::__libcpp_compressed_pair_imp<const std::__1::packaged_task<int()> &, 
     const std::__1::allocator<std::__1::packaged_task<int()> > &, 0, 0>' 
     requested here 
      : base(__pc, _VSTD::move(__first_args), _VSTD::move(__second_args), 
      ^
/usr/bin/../lib/c++/v1/functional:996:11: note: in instantiation of function 
     template specialization 
     'std::__1::__compressed_pair<std::__1::packaged_task<int()>, 
     std::__1::allocator<std::__1::packaged_task<int()> > 
     >::__compressed_pair<const std::__1::packaged_task<int()> &, const 
     std::__1::allocator<std::__1::packaged_task<int()> > &>' requested here 
     : __f_(piecewise_construct, _VSTD::forward_as_tuple(__f), 
     ^
/usr/bin/../lib/c++/v1/functional:1035:17: note: in instantiation of member 
     function 'std::__1::__function::__func<std::__1::packaged_task<int()>, 
     std::__1::allocator<std::__1::packaged_task<int()> >, void()>::__func' 
     requested here 
    ::new (__p) __func(__f_.first(), __f_.second()); 
       ^
/usr/bin/../lib/c++/v1/functional:1277:26: note: in instantiation of member 
     function 'std::__1::__function::__func<std::__1::packaged_task<int()>, 
     std::__1::allocator<std::__1::packaged_task<int()> >, void()>::__clone' 
     requested here 
      ::new (__f_) _FF(_VSTD::move(__f)); 
         ^
/usr/bin/../lib/c++/v1/memory:1681:31: note: in instantiation of function 
     template specialization 'std::__1::function<void 
    ()>::function<std::__1::packaged_task<int()> >' requested here 
      ::new((void*)__p) _Up(_VSTD::forward<_Args>(__args)...); 
          ^
/usr/bin/../lib/c++/v1/memory:1608:18: note: in instantiation of function 
     template specialization 'std::__1::allocator<std::__1::function<void()> 
     >::construct<std::__1::function<void()>, std::__1::packaged_task<int()> 
     >' requested here 
      {__a.construct(__p, _VSTD::forward<_Args>(__args)...);} 
       ^
/usr/bin/../lib/c++/v1/memory:1492:14: note: in instantiation of function 
     template specialization 
     'std::__1::allocator_traits<std::__1::allocator<std::__1::function<void 
    ()> > >::__construct<std::__1::function<void()>, 
     std::__1::packaged_task<int()> >' requested here 
      {__construct(__has_construct<allocator_type, pointer, _Args...>(), 
      ^
/usr/bin/../lib/c++/v1/vector:1519:25: note: in instantiation of function 
     template specialization 
     'std::__1::allocator_traits<std::__1::allocator<std::__1::function<void 
    ()> > >::construct<std::__1::function<void()>, 
     std::__1::packaged_task<int()> >' requested here 
     __alloc_traits::construct(this->__alloc(), 
         ^
main.cpp:19:6: note: in instantiation of function template specialization 
     'std::__1::vector<std::__1::function<void()>, 
     std::__1::allocator<std::__1::function<void()> > 
     >::emplace_back<std::__1::packaged_task<int()> >' requested here 
     vec.emplace_back(std::move(task)); 
      ^
/usr/bin/../lib/c++/v1/future:1956:5: note: function has been explicitly marked 
     deleted here 
    packaged_task(const packaged_task&) = delete; 
    ^
2 errors generated. 
+0

能否請您包括確切的錯誤消息? –

+0

而這只是兩個錯誤。 –

+2

'std :: packaged_task '是僅移動的。 'std :: function '只適用於可複製函子(並且與'Sig'兼容)。 –

回答

9

的神祕模板的錯誤信息應該是可轉換到std::function<void()>,是嗎?

function相關的構造函數需要它的參數是拷貝構造和packaged_task不是拷貝構造,這只是MoveConstructible,因爲它的拷貝構造函數和拷貝賦值運算符將被刪除。這是function的一個不幸需求,但由於使用類型擦除來抽象出包裝的可調用對象的細節,因此function必須是可複製的。

在這個過程中,C++ 0x草稿不需要CopyConstructible,但它被添加到DR 1287的最終C++ 11標準中,所以這是我的錯,對不起;-)以前的啓用概念的草稿需要CopyConstructible這個概念,但是當概念從草稿中刪除時,這個概念就會丟失。

1

今天我有這個確切的問題。當根據異步服務實現同步調用時,顯而易見的事情是嘗試將處理函數中的packaged_task存儲在處理函數中,以便在異步處理程序完成時調用者的將來可以做好準備。

不幸的是,C++ 11(和14)不允許這樣做。追蹤它花費我近一天的開發時間,並且這個過程讓我得到了這個答案。

我敲了一個解決方案 - 一個替代std :: function與std :: packaged_task專業化。

感謝yngum和Jonathan發佈問題和答案。

代碼:

// general template form 
template<class Callable> 
struct universal_call; 

// partial specialisation to cover most cases 
template<class R, class...Args> 
struct universal_call<R(Args...)> { 
    template<class Callable> 
    universal_call(Callable&& callable) 
    : _impl { std::make_shared<model<Callable>>(std::forward<Callable>(callable)) } 
    {} 

    R operator()(Args&&...args) const { 
     return _impl->call(std::forward<Args>(args)...); 
    } 
private: 
    struct concept { 
     virtual R call(Args&&...args) = 0; 
     virtual ~concept() = default; 
    }; 

    template<class Callable> 
    struct model : concept { 
     model(Callable&& callable) 
     : _callable(std::move(callable)) 
     {} 
     R call(Args&&...args) override { 
      return _callable(std::forward<Args>(args)...); 
     } 
     Callable _callable; 
    }; 

    std::shared_ptr<concept> _impl; 
}; 

// pathalogical specialisation for std::packaged_task - 
// erases the return type from the signature 
template<class R, class...Args> 
struct universal_call<std::packaged_task<R(Args...)>> 
: universal_call<void(Args...)> 
{ 
    using universal_call<void(Args...)>::universal_call; 
}; 

// (possibly) helpful function 
template<class F> 
universal_call<F> make_universal_call(F&& f) 
{ 
    return universal_call<F>(std::forward<F>(f)); 
}