我想要一个包装线程函数,即由执行一些额外操作的线程执行的函数,然后调用用户函数。
template<class F, class... Args>
void wrapper(F&& user_function, Args&&... args) {
// do some extra stuff
user_function(args); // maybe I need to forward args
// do some extra stuff
}
好吧,这可能是一个很好的包装器,所以我需要一个使用这个包装器函数的管理器,并允许用户生成自己的线程:
class ThreadManager {
public:
template<class F, class... Args>
std::thread newThread(F&& f, Args&&... args) {
return std::thread(thread_wrapper<F,Args...>, std::forward<F>(f), std::forward<Args>(args)...);
}
};
这样线程管理器应该产生一个使用包装器函数的线程,而该包装函数反过来做额外的工作并调用用户函数。
但编译器现在说:尝试使用已删除的功能。
错误在线程头中:
template <class _Fp, class ..._Args, size_t ..._Indices>
inline _LIBCPP_INLINE_VISIBILITY
void
__thread_execute(tuple<_Fp, _Args...>& __t, __tuple_indices<_Indices...>)
{
__invoke(_VSTD::move(_VSTD::get<0>(__t)), _VSTD::move(_VSTD::get<_Indices>(__t))...);
}
我错过了什么/做错了什么?
[编辑]
使用测试:
void foo(int i) {
std::cout << "foo: " << i << std::endl;
}
int main(int argc, const char *argv[]) {
ThreadManager mgr;
auto t = mgr.newThread(foo, 10);
t.detach();
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
return 0;
}
我正在使用带有LLVM编译器的Xcode 7.1,但在FreeBSD clang 3.3上也失败了。
Xcode错误是:
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin /../ include / c ++ / v1 / thread:337:5:错误:尝试使用已删除的功能 __invoke(_VSTD :: move(_VSTD :: get&lt; 0&gt;(__ t)),_ VSTD :: move(_VSTD :: get&lt; _Indices&gt;(__ t))...); ^ /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/thread:347:5:注意:在实例化函数模板特化'std :: __ 1: :__ thread_execute'在这里请求 __thread_execute(* __ p,_Index()); ^ /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/thread:359:42:注意:在实例化函数模板特化'std :: __ 1: :__ thread_proxy&gt;'这里要求 int __ec = pthread_create(&amp; __ t_,0,&amp; __ thread_proxy&lt; _Gp&gt;,__ p.get());
答案 0 :(得分:1)
我不确定在您的示例中导致“尝试使用已删除的函数”的原因是什么,我得到与std::thread
的绑定机制相关的其他错误。
看起来你拼出thread_wrapper
的模板参数的方式与std::thread
的构造函数没有关系 - 特别是当它在内部使用简化的std::bind
时。完美转发的函数类型和std::decay
ed函数指针的混合似乎扰乱了std::result_of
。
我们可以通过在std::decay
中自行应用newThread
来使其工作:
return std::thread( thread_wrapper<typename std::decay<F>::type,
typename std::decay<Args>::type...>,
std::forward<F>(f),
std::forward<Args>(args)... );
...但说实话,我并不完全确定为什么有效。
或者,通过一些间接和更多转发,我们可以避免拼出模板参数。
我们只需要一个转发到thread_wrapper
(或C ++ 14中的多态lambda)的仿函数:
struct wrapper_helper {
template<class F, class... Args>
void operator()(F&& f, Args&&... args) const {
thread_wrapper(std::forward<F>(f), std::forward<Args>(args)...);
}
};
并在newThread
:
return std::thread(wrapper_helper{}, std::forward<F>(f), std::forward<Args>(args)...);
以下是显示按值,参考和右值引用传递的参数的完整示例:http://coliru.stacked-crooked.com/a/b75d5a264f583237
注意:对于仅std::unique_ptr
这样的仅限移动类型,您肯定希望在args...
转发thread_wrapper
。