2013-06-03 4 views
7

나는 std::packaged_task를 이동하는 것을 시도하고, std::packaged_taskvoid operator()(ArgTypes... args)가 과부하 때문에, 그것은 예, std::function<void()>에 convertable해야 하는가?표준 : 기능과 표준 : packaged_task 변환

이것은 MSVC와 Clang에서 컴파일되지 않습니다. MSVC는 void를 int로 변환 할 수 없다고 불평하고, clang은 std::packaged_task의 삭제 된 복사본 생성자를 불평합니다. std::vector::push_back의 버전을 옮기지 말아야합니까? 무슨 일이 벌어지고 있니?이게 버그 야? 여기

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

네, 그것은 std::function<void()>에 convertable해야 그 소리

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

당신은 정확한 오류 메시지를 포함시겠습니까? –

+0

그리고 그것은 단지 두 가지 오류 때문이었습니다. –

+2

'std :: packaged_task '은 (는) 이동 전용입니다. 'std :: function '는 복사 가능한 펑터에서만 작동하며 ('Sig'와 호환 가능합니다). –

답변

9

의 비밀 템플릿 오류 메시지인가? 자사의 복사 생성자와 대입 연산자를 복사하기 때문에 삭제, 그것은 단지 MoveConstructible입니다

번호 function의 관련 생성자는 CopyConstructible (복사 가능 생성자)로 인수가 필요하며 packaged_task는 CopyConstructible (복사 가능 생성자)이 아니다. 이는 function의 불행한 요구 사항이지만 랩핑 된 호출 가능 객체의 세부 사항을 추상화하기 위해 유형 삭제를 사용하기 때문에 function이 복사 가능해야합니다.

매우 늦게까지 C++ 0x 초안은 CopyConstructible을 요구하지 않았지만 DR 1287에 의해 최종 C++ 11 표준에 추가되었으므로 미안합니다 .- 초기 컨셉 지원 초안 CopyConstructible 개념을 필요로하지만이 필요했지만 개념이 초안에서 제거되었을 때 잃어 버렸습니다.

1

오늘이 정확한 문제가있었습니다. 비동기 서비스와 관련하여 동기 호출을 구현할 때 명백하게해야 할 일은 비동기 처리기가 완료 될 때 호출자의 미래를 준비 할 수 있도록 처리 함수에 packaged_task를 저장하는 것입니다.

불행히도 C++ 11 (및 14)은 이것을 허용하지 않습니다. 추적을 통해 개발 시간이 거의 하루가 걸렸고 프로세스를 통해이 대답을 얻을 수있었습니다.

나는 std :: packaged_task의 특성화를 사용하여 std :: function을 대체하는 솔루션을 고안했다.

질문과 답변을 게시 해 주신 yngum과 Jonathan에게 감사드립니다.

코드 :

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