Std::function与Std::packaged_task的转换
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
的相关构造函数要求其参数为CopyConstructible,而packaged_task
不是CopyConstructible,它只有MoveConstructible,因为它的复制构造函数和复制赋值操作符被删除了。这是function
的一个不幸的要求,但function
必须是可复制的,因为使用类型擦除来抽象包装的可调用对象的细节。
直到相当晚的过程中,c++ 0x草案不需要CopyConstructible,但它被DR 1287添加到最终的c++ 11标准中,所以这是我的错,对不起;-)一个早期的支持概念的草案有需要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));
}
今天我有类似的问题。使用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)();
});
- 将无符号char*转换为std::istream*C++
- 将 int 数组转换为 std::vector<int*>
- 如何将这个std::字符串转换为std::基本字符串
- 哪些类型可以转换为std::any
- 如何在对<char>C++程序进行逆向工程的同时将 std::basic_string 转换为 Rust 可读值?
- 转换函数,将 std::数组的双精度作为参数或双精度作为参数单独转换
- 将函数参数"const char*"转换为"std::string_view"是
- 错误 C2679:二进制"<<":未找到采用类型 'std::string_view' 的右侧操作数的运算符(或者没有可接受的转换)
- 字符转换功能 std::isupper() & std::islower() C++17
- 将函数包装器转换为 std::function
- 如何将 std::ifstream 转换为 std::basic_istream<CharT, Traits>&?
- 显式 std::exception_ptr 转换为 bool 不存在.VS2010 错误?
- 如何将唯一指针的 std::vector 转换为原始指针的 std::span?
- std::转换move构造函数的模板专业化的变体
- STD ::转换如何用特定值初始化函子
- 对C++字符串使用 std 转换
- 等价于元组的std::转换
- std::转换为任意容器
- std::转换顺序保证
- std::转换产生奇怪的输出