`std :: packaged_task`是否需要CopyConstructible构造函数参数?

时间:2013-07-05 17:15:14

标签: c++ c++11 future packaged-task

我有这个最小的不工作的代码示例

#include <future>

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

为什么不编译(在gcc 4.8.1上)?我怀疑,原因是,std::packaged_task将lambda内部存储在需要std::function参数的CopyConstructible内。但是,std::packaged_task仅限移动。这是一个错误吗?标准对此有何评价?在我看来,std::packaged_task不应该需要CopyConstructible参数,但MoveConstructible参数就足够了。

顺便说一句,当我用std::packaged_task<int()>替换std::packaged_task<void()>时,一切都编译得很好。

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{} );
}

3 个答案:

答案 0 :(得分: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();
}

答案 1 :(得分:0)

没有。您无法将packaged_task<int ()>移动到packaged_task<void ()>。这些类型是无关的,不能相互移动分配或移动构造。如果您出于某种原因确实想要这样做,您可以“吞下”int ()的结果this

答案 2 :(得分: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的行为相同。

并且此调用可以抛出

  

fstd::bad_alloc的复制或移动构造函数抛出的任何异常(如果内存)   无法分配内部数据结构。

这隐含意味着,如果将左值引用传递给函数,则F类型必须至少为MoveConstructibleCopyConstructible

因此,它不是一个错误,它只是没有精确指定。要解决将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)(); } };
}