[英]std::function and std::packaged_task conversion
我試圖將std::packaged_task
移動到std::function<void()>
的std::vector
中,因為std::packaged_task
重載了void operator()( ArgTypes... args )
,它應該是可轉換的到std::function<void()>
,是嗎?
這在 MSVC 和 Clang 上都不能編譯,MSVC 抱怨無法將 void 轉換為 int,clang 抱怨已刪除std::packaged_task
復制構造函數,不應該在此處調用std::vector::push_back
移動版本嗎? 這是怎么回事,這是bug嗎?
int main ()
{
std::vector<std::function<void()>> vec;
std::packaged_task<int()> task( [] { return 100; } );
vec.push_back( std::move(task) );
}
這是 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.
它應該可以轉換為
std::function<void()>
,是嗎?
不是。 function
的相關構造function
要求它的參數是CopyConstructible,而packaged_task
不是CopyConstructible,它只是MoveConstructible,因為它的拷貝構造函數和拷貝賦值運算符被刪除了。 這是function
一個不幸要求,但對於function
可復制來說是必要的,因為使用類型擦除來抽象出包裝的可調用對象的細節。
直到過程已經很晚了的C ++ 0x草案沒有要求拷貝構造,但它被添加到最終的C ++標准的11 DR 1287所以這是我的錯,對不起;-)較早啟用概念草案所要求的CopyConstructible
概念,但是當概念從草案中刪除時,這個概念就消失了。
我今天遇到了這個確切的問題。 在異步服務方面實現同步調用時,顯而易見的事情是嘗試將 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));
}
您可以創建一個std::function<void()>
來調用std::packaged_task::operator()
作為解決方法:
#include <functional>
#include <future>
#include <vector>
int main () {
typedef std::packaged_task<int()> Task;
std::vector<std::function<void()>> vec;
Task task( [] { return 100; } );
vec.emplace_back( std::bind(&Task::operator(), &task) );
for( auto& t : vec )
t();
}
使用-pthread
編譯。
今天我遇到了類似的問題。 使用 c++14 和 lambda 捕獲初始化,我們可以編寫:
std::vector<std::function<void()>> vec;
using task_t = std::packaged_task<int()>;
task_t task([] { return 100; });
vec.emplace_back( [t = std::make_shared<task_t>(std::move(task))]() {
(*t)();
});
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.