2013-07-05 113 views
3

`std :: packaged_task`是否需要一個CopyConstructible構造函數參數?

#include <future> 

int main() 
{ 
    auto intTask = std::packaged_task<int()>([]()->int{ return 5; }); 
    std::packaged_task<void()> voidTask{ std::move(intTask) }; 
} 

爲什麼不把它編譯(海合會4.8.1)的代碼,這個最小的不工作的例子嗎?我懷疑,原因是,std::packaged_task將lambda內部存儲在std::function之內,該參數需要CopyConstructible參數。但是,std::packaged_task是僅移動的。這是一個錯誤?標準對此有何評論?在我看來,std::packaged_task不應該需要CopyConstructible參數,但MoveConstructible論據應該足夠了。

順便說一下,當我用std::packaged_task<void()>替換std::packaged_task<int()>時,一切都很好編譯。

GCC 4.8.1是給我這個錯誤消息:

In file included from /usr/include/c++/4.6/future:38:0, 
       from ../cpp11test/main.cpp:160: 
/usr/include/c++/4.6/functional: In static member function 'static void  std::_Function_base::_Base_manager<_Functor>::_M_clone(std::_Any_data&, const std::_Any_data&, std::false_type) [with _Functor = std::packaged_task<int()>, std::false_type = std::integral_constant<bool, false>]': 
/usr/include/c++/4.6/functional:1652:8: instantiated from 'static bool std::_Function_base::_Base_manager<_Functor>::_M_manager(std::_Any_data&, const std::_Any_data&, std::_Manager_operation) [with _Functor = std::packaged_task<int()>]' 
/usr/include/c++/4.6/functional:2149:6: instantiated from 'std::function<_Res(_ArgTypes ...)>::function(_Functor, typename std::enable_if<(! std::is_integral<_Functor>::value), std::function<_Res(_ArgTypes ...)>::_Useless>::type) [with _Functor = std::packaged_task<int()>, _Res = void, _ArgTypes = {}, typename std::enable_if<(! std::is_integral<_Functor>::value), std::function<_Res(_ArgTypes ...)>::_Useless>::type = std::function<void()>::_Useless]' 
/usr/include/c++/4.6/bits/shared_ptr_base.h:410:4: instantiated from 'std::_Sp_counted_ptr_inplace<_Tp, _Alloc, _Lp>::_Sp_counted_ptr_inplace(_Alloc, _Args&& ...) [with _Args = {std::packaged_task<int()>}, _Tp = std::__future_base::_Task_state<void()>, _Alloc = std::allocator<std::__future_base::_Task_state<void()> >, __gnu_cxx::_Lock_policy _Lp = (__gnu_cxx::_Lock_policy)2u]' 
/usr/include/c++/4.6/bits/shared_ptr_base.h:518:8: instantiated from 'std::__shared_count<_Lp>::__shared_count(std::_Sp_make_shared_tag, _Tp*, const _Alloc&, _Args&& ...) [with _Tp = std::__future_base::_Task_state<void()>, _Alloc = std::allocator<std::__future_base::_Task_state<void()> >, _Args = {std::packaged_task<int()>}, __gnu_cxx::_Lock_policy _Lp = (__gnu_cxx::_Lock_policy)2u]' 
/usr/include/c++/4.6/bits/shared_ptr_base.h:987:35: instantiated from 'std::__shared_ptr<_Tp, _Lp>::__shared_ptr(std::_Sp_make_shared_tag, const _Alloc&, _Args&& ...) [with _Alloc = std::allocator<std::__future_base::_Task_state<void()> >, _Args = {std::packaged_task<int()>}, _Tp = std::__future_base::_Task_state<void()>, __gnu_cxx::_Lock_policy _Lp = (__gnu_cxx::_Lock_policy)2u]' 
/usr/include/c++/4.6/bits/shared_ptr.h:317:64: instantiated from 'std::shared_ptr<_Tp>::shared_ptr(std::_Sp_make_shared_tag, const _Alloc&, _Args&& ...) [with _Alloc = std::allocator<std::__future_base::_Task_state<void()> >, _Args = {std::packaged_task<int()>}, _Tp = std::__future_base::_Task_state<void()>]' 
/usr/include/c++/4.6/bits/shared_ptr.h:535:39: instantiated from 'std::shared_ptr<_Tp> std::allocate_shared(const _Alloc&, _Args&& ...) [with _Tp = std::__future_base::_Task_state<void()>, _Alloc = std::allocator<std::__future_base::_Task_state<void()> >, _Args = {std::packaged_task<int()>}]' 
/usr/include/c++/4.6/bits/shared_ptr.h:551:42: instantiated from 'std::shared_ptr<_Tp1> std::make_shared(_Args&& ...) [with _Tp = std::__future_base::_Task_state<void()>, _Args = {std::packaged_task<int()>}]' 
/usr/include/c++/4.6/future:1223:66: instantiated from 'std::packaged_task<_Res(_ArgTypes ...)>::packaged_task(_Fn&&) [with _Fn = std::packaged_task<int()>, _Res = void, _ArgTypes = {}]' 
../cpp11test/main.cpp:165:61: instantiated from here 
/usr/include/c++/4.6/functional:1616:4: error: use of deleted function 'std::packaged_task<_Res(_ArgTypes ...)>::packaged_task(std::packaged_task<_Res(_ArgTypes ...)>&) [with _Res = int, _ArgTypes = {}, std::packaged_task<_Res(_ArgTypes ...)> = std::packaged_task<int()>]' 
/usr/include/c++/4.6/future:1244:7: error: declared here 

更新:我寫了下面的測試程序。它似乎支持原因缺失CopyConstructability的假設。同樣,可以構造std::packaged_task的對象類型的要求是什麼?

#include <future> 

struct Functor { 
    Functor() {} 
    Functor(const Functor &) {} // without this line it doesn't compile 
    Functor(Functor &&) {} 
    int operator()(){ return 5; } 
}; 

int main() { 
    auto intTask = std::packaged_task<int()>(Functor{}); 
} 
+0

我修改我的答案。你正在徘徊在'explicit'構造函數中。 –

+0

你爲什麼試圖將std :: packaged_task 轉換成std :: packaged_task ? –

+0

其實我想在'std :: packaged_task '的隊列中爲任何類型'T'推送'std :: packaged_task '。我需要一個通用類型的隊列元素。目標是實現一個線程池,它在內部保存一個併發的任務隊列。 'std :: function'將不夠用,因爲我想爲計算結果返回'std :: futures'。 –

回答

0

標準的結果(如N3690)的不

有關類型 F的要求,明確規定什麼
template <class R, class... ArgTypes> 
template <class F> 
packaged_task<R(ArgTypes...)>::packaged_task(F&& f); 

(見30.6.9.1),但它指出

調用的f副本應當相同的調用f

而且這種電話可以拋出

通過副本拋出的異常或移動的f,或std::bad_alloc構造如果內部數據結構存儲 無法分配。

這隱含意味着類型F必須至少MoveConstructible,或CopyConstructible,如果左值參考被傳遞給該函數。

因此,這不是一個錯誤,它只是沒有明確指出。爲了解決把一個std::packaged_task<int()>std::packaged_task<void()>只是包裝第一成shared_ptr這樣的問題:

#include <future> 
#include <memory> 

int main() 
{ 
    auto intTask = std::make_shared<std::packaged_task<int()>>( 
     []()->int{ return 5; }); 
    std::packaged_task<void()> voidTask{ [=]{ (*intTask)(); } }; 
} 
2

事實上,packaged_task只有一個移動的構造函數(30.6.9/2):

template <class F> explicit packaged_task(F&& f);

然而,你的問題是explicit構造。所以寫這樣的:

std::packaged_task<int()> pt([]() -> int { return 1; }); 

完整的示例:

#include <future> 
#include <thread> 

int main() 
{ 
    std::packaged_task<int()> intTask([]() -> int { return 5; }); 
    auto f = intTask.get_future(); 
    std::thread(std::move(intTask)).detach(); 
    return f.get(); 
} 
+0

這並不能解決問題。由於main()函數中的第二行,代碼無法編譯。我想將'std :: packaged_task '移動到'std :: packaged_task '中。我在我的問題的評論中解釋了它的原因。 –

0

號你就不能移動packaged_task<int()>packaged_task<void()>。這些類型是不相關的,不能彼此移動分配或移動構建。如果由於某種原因真的想這樣做,你可以「吞」了int()this

+0

不幸的是,你的鏈接中的解決方案對我來說不起作用,因爲在我的問題中執行'voidTask'之前'intTask'將會超出範圍。 '[&]'捕獲不好。但'[=]'也不會,因爲'std :: packaged_task'不是'可複製的'。也許一個'std :: shared_ptr'解決方案可以工作。 –

+0

你根本無法做到這一點,類型不兼容。您將需要提供一種間接級別,將這兩種類型包裝到一個通用類型的實例中。這個新的「任務」類型的返回類型需要被詢問實際的運行時類型。 –

相關問題