2013-06-03 35 views
7

Tôi cố gắng để di chuyển một std::packaged_task thành một std::vector của std::function<void()>, vì std::packaged_task đã void operator()(ArgTypes... args) quá tải, nó phải là convertable để std::function<void()>, đúng không?std :: chức năng và std :: packaged_task chuyển đổi

Điều này không biên dịch cả trên MSVC và Clang, MSVC phàn nàn về không thể chuyển đổi void thành int, clang than phiền bản sao đã xóa cho std::packaged_task, không được di chuyển phiên bản std::vector::push_back được gọi ở đây? những gì đang xảy ra, đây có phải là lỗi không?

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

Dưới đây là những thông điệp mẫu báo lỗi khó hiểu cho vang

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

thể bạn vui lòng cung cấp các thông báo lỗi chính xác? –

+0

Và đó chỉ là hai lỗi. –

+2

'std :: packaged_task 'là chỉ di chuyển. 'std :: function ' chỉ hoạt động với các functors có thể sao chép được (và tương thích với 'Sig'). –

Trả lời

9

nó phải được convertable để std::function<void()>, đúng không?

số Các nhà xây dựng có liên quan của function đòi hỏi đối số của nó là CopyConstructible và packaged_task không CopyConstructible, nó chỉ là MoveConstructible, vì copy constructor của nó và sao chép toán tử gán sẽ bị xóa. Đây là một yêu cầu không may của function nhưng cần thiết cho function để có thể sao chép được, do sử dụng loại xóa để trừu tượng hóa các chi tiết của đối tượng có thể gọi được bao bọc.

Cho đến khá muộn trong quá trình bản nháp C++ 0x không yêu cầu CopyConstructible nhưng nó đã được thêm vào tiêu chuẩn C++ 11 cuối cùng bởi DR 1287 vì vậy đó là lỗi của tôi, xin lỗi ;-) yêu cầu khái niệm CopyConstructible nhưng bị mất khi khái niệm bị xóa khỏi bản nháp.

1

Tôi đã gặp sự cố chính xác này ngay hôm nay. Khi thực hiện một cuộc gọi đồng bộ về một dịch vụ không đồng bộ, điều hiển nhiên cần làm là cố gắng lưu trữ một packaged_task trong một hàm xử lý để tương lai của người gọi có thể sẵn sàng khi trình xử lý không đồng bộ hoàn tất.

Thật không may C++ 11 (và 14) không cho phép điều này. Theo dõi nó xuống chi phí cho tôi gần một ngày của thời gian phát triển, và quá trình dẫn tôi đến câu trả lời này.

Tôi đã giải quyết một giải pháp - thay thế cho std :: function với chuyên môn cho std :: packaged_task.

Cảm ơn cả yngum và Jonathan vì đã đăng câu hỏi và câu trả lời.

mã:

// 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)); 
} 
Các vấn đề liên quan