2013-06-03 18 views
7

Sto cercando di spostare un std::packaged_task in un std::vector di std::function<void()>, perché std::packaged_task ha void operator()(ArgTypes... args) sovraccarico, dovrebbe essere convertibile a std::function<void()>, sì?std :: funzione e std :: packaged_task conversione

Ciò non compilare sia in MSVC e Clang, MSVC lamenta di non in grado di convertire vuoto a int, clang lamenta cancellato costruttore di copia per std::packaged_task, non dovrebbe muoversi versione di std::vector::push_back essere chiamato qui? cosa sta succedendo, questo è un bug?

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

Ecco i messaggi di errore del modello criptici per clang

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

la prego di includere i messaggi di errore esatto? –

+0

E quello era solo per due errori. –

+2

'std :: packaged_task ' è solo mossa. 'std :: function ' funziona solo con i funtori copiabili (e compatibili con 'Sig'). –

risposta

9

dovrebbe essere convertibile a std::function<void()>, sì?

No. Il costruttore dedicata del function richiede il suo argomento di essere CopyConstructible e packaged_task non è CopyConstructible, è solo MoveConstructible, perché il suo costruttore di copia e copiare operatore di assegnamento vengono cancellati. Si tratta di uno sfortunato requisito di function ma necessario affinché function sia copiabile, a causa dell'utilizzo della cancellazione di tipo per astrarre i dettagli dell'oggetto callable avvolto.

Fino a poco tempo fa la bozza C++ 0x non richiedeva CopyConstructible ma è stata aggiunta allo standard C++ 11 finale di DR 1287 quindi è colpa mia, scusa ;-) Un progetto precedente con bozza abilitata aveva richiesto il concetto CopyConstructible, ma che si è perso quando i concetti sono stati rimossi dal progetto.

1

Ho avuto questo problema esatto oggi. Quando si implementa una chiamata sincrona in termini di servizio asincrono, la cosa ovvia da fare è provare a memorizzare un pacchetto_pacchetto in una funzione di gestore in modo che il futuro del chiamante possa essere reso pronto al completamento del gestore asincrono.

Sfortunatamente C++ 11 (e 14) non lo consentono. Rintracciarlo mi è costato quasi un giorno di tempo di sviluppo e il processo mi ha portato a questa risposta.

Ho eliminato una soluzione, una sostituzione per std :: function con una specializzazione per std :: packaged_task.

Grazie a yngum e Jonathan per aver postato la domanda e la risposta.

codice:

// 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)); 
} 
Problemi correlati