2013-06-03 22 views
7

Próbuję przenieść std::packaged_task w std::vector z std::function<void()>, ponieważ std::packaged_task został void operator()(ArgTypes... args) przeciążony, powinno być convertable do std::function<void()>, tak?std :: Funkcja i std :: packaged_task konwersja

to robi skompilować zarówno na MSVC i Clang, MSVC narzeka nie można przekonwertować na int nieważne, dzyń skarg wnoszonych usunięte konstruktor kopiujący dla std::packaged_task, nie powinien poruszać wersja std::vector::push_back być nazywane tutaj? co się dzieje, czy to błąd?

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

Oto tajemnicze komunikaty o błędach szablon dla brzękiem

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

mógłbyś zawierać dokładne komunikaty o błędach? –

+0

I to było tylko dla dwóch błędów. –

+2

'std :: packaged_task ' jest tylko ruch. 'std :: function ' działa tylko z funktorami do kopiowania (i które są kompatybilne z 'Sig'). –

Odpowiedz

9

Należy convertable do std::function<void()>, tak?

nr Odpowiednie konstruktor function wymaga jej argumentu być CopyConstructible i packaged_task nie CopyConstructible, tylko MoveConstructible, ponieważ konstruktor kopiowania i skopiować operatora przypisania zostały usunięte. Jest to niefortunne wymaganie od function, ale konieczne jest, aby function było kopiowalne, z powodu użycia funkcji usuwania typu w celu usunięcia szczegółów owiniętego obiektu wywoływanego.

Do czasu dość późnego procesu szkic C++ 0x nie wymagał funkcji CopyConstructible, ale został dodany do ostatecznego standardu C++ 11 przez DR 1287, więc to moja wina, przepraszam ;-) Wcześniejsza wersja z włączoną koncepcją miał wymaga koncepcji CopyConstructible, ale to zaginęło, gdy koncepcje zostały usunięte z wersji roboczej.

1

Dziś miałem dokładnie ten problem. Podczas implementacji wywołania synchronicznego pod względem usługi asynchronicznej oczywiste jest, aby spróbować zapisać parametr packaged_task w funkcji obsługi, aby można było przygotować do przyszłości wywołującego, gdy zakończy się procedura obsługi asynchronicznej.

Niestety C++ 11 (i 14) nie pozwalają na to. Śledzenie go kosztowało mnie prawie dzień rozwoju, a proces ten doprowadził mnie do tej odpowiedzi.

Rozwiązałem rozwiązanie - zamiennik dla std :: function ze specjalizacją dla std :: packaged_task.

Dziękuję yungowi i Jonathanowi za opublikowanie pytania i odpowiedzi.

Kod:

// 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)); 
} 
Powiązane problemy