[英]How to pass variadic args to a std::thread?
I would like to use my own Thread implementation by wrapping the std::thread class from C++11 so I will be able handle exceptions like I want.我想通过包装 C++11 中的 std::thread 类来使用我自己的 Thread 实现,这样我就可以像我想要的那样处理异常。
Here is my wrap class:这是我的包装类:
#include <Types.hpp>
#include <thread>
#include <exception>
#include <functional>
class Thread
{
private:
std::exception_ptr exceptionPtr;
std::thread thread;
public:
using Id = std::thread::id;
using NativeHandleType = std::thread::native_handle_type;
Thread() noexcept = default;
Thread(Thread &&t) noexcept :
exceptionPtr(std::move(t.exceptionPtr)),
thread(std::move(t.thread))
{
}
Thread &operator =(Thread &&t) noexcept
{
exceptionPtr = std::move(t.exceptionPtr);
thread = std::move(t.thread);
return *this;
}
template<typename Callable, typename... Args>
Thread(Callable &&f, Args &&... args) :
exceptionPtr(nullptr),
thread([&](Callable &&f, Args &&... args)
{
try
{
std::once_flag flag;
std::call_once(flag, f, args...);
}
catch (...)
{
exceptionPtr = std::current_exception();
}
}, f, args...)
{
if (exceptionPtr != nullptr)
{
std::rethrow_exception(exceptionPtr);
}
}
bool joinable() const noexcept
{
return thread.joinable();
}
void join()
{
thread.join();
}
void detach()
{
thread.detach();
}
Id getId() const noexcept
{
return thread.get_id();
}
NativeHandleType nativeHandle()
{
return thread.native_handle();
}
static uint32_t hardwareConcurrency() noexcept
{
return std::thread::hardware_concurrency();
}
static void wait(Time t)
{
std::this_thread::sleep_for(t);
}
};
It works pretty well if there is no argument:如果没有争论,它工作得很好:
Thread([&]() { /* do something */ }).detach();
... but if I try to pass variadic arguments: ...但是如果我尝试传递可变参数:
Thread(&GUI::refreshTask, this, refreshDelay).detach();
... I get an error at compile time: ...我在编译时遇到错误:
buildroot-2014.02/output/host/usr/i586-buildroot-linux-uclibc/include/c++/4.8.2/functional: In instantiation of 'struct std::_Bind_simple)(std::chrono::duration >);
buildroot-2014.02/output/host/usr/i586-buildroot-linux-uclibc/include/c++/4.8.2/functional: 在'struct std::_Bind_simple)(std::chrono::duration >); 的实例化中Args = {CRH::GUI const, std::chrono::duration >&}]::__lambda1(void (CRH::GUI:: )(std::chrono::duration >), CRH::GUI , std::chrono::duration >)>': buildroot-2014.02/output/host/usr/i586-buildroot-linux-uclibc/include/c++/4.8.2/thread:137:47: required from 'std::thread::thread(_Callable&&, _Args&&...) [with _Callable = CRH::Thread::Thread(Callable&&, Args&&...) [with Callable = void (CRH::GUI:: )(std::chrono::duration >);
Args = {CRH::GUI const, std::chrono::duration >&}]::__lambda1(void (CRH::GUI:: )(std::chrono::duration >), CRH::GUI , std ::chrono::duration >)>': buildroot-2014.02/output/host/usr/i586-buildroot-linux-uclibc/include/c++/4.8.2/thread:137:47: 'std::thread 需要::thread(_Callable&&, _Args&&...) [with _Callable = CRH::Thread::Thread(Callable&&, Args&&...) [with Callable = void (CRH::GUI:: )(std::chrono::持续时间 >); Args = {CRH::GUI const, std::chrono::duration >&}]::__lambda1;
Args = {CRH::GUI const, std::chrono::duration >&}]::__lambda1; _Args = {void (CRH::GUI:: &)(std::chrono::duration >), CRH::GUI const&, std::chrono::duration >&}]' /home/cyril/Documents/crh-2016/src/robot2/../core/Thread.hpp:72:30: required from 'CRH::Thread::Thread(Callable&&, Args&&...) [with Callable = void (CRH::GUI:: )(std::chrono::duration >);
_Args = {void (CRH::GUI:: &)(std::chrono::duration >), CRH::GUI const&, std::chrono::duration >&}]' /home/cyril/Documents/crh -2016/src/robot2/../core/Thread.hpp:72:30: 来自'CRH::Thread::Thread(Callable&&, Args&&...) [with Callable = void (CRH::GUI:: )(std::chrono::duration >); Args = {CRH::GUI const, std::chrono::duration >&}]' src/core/GUI.cpp:90:57: required from here buildroot-2014.02/output/host/usr/i586-buildroot-linux-uclibc/include/c++/4.8.2/functional:1697:61: error: no type named 'type' in 'class std::result_of)(std::chrono::duration >);
Args = {CRH::GUI const, std::chrono::duration >&}]' src/core/GUI.cpp:90:57: 从这里需要 buildroot-2014.02/output/host/usr/i586-buildroot- linux-uclibc/include/c++/4.8.2/functional:1697:61: 错误:'class std::result_of)(std::chrono::duration >) 中没有名为'type'的类型; Args = {CRH::GUI const, std::chrono::duration >&}]::__lambda1(void (CRH::GUI:: )(std::chrono::duration >), CRH::GUI , std::chrono::duration >)>' typedef typename result_of<_Callable(_Args...)>::type result_type;
Args = {CRH::GUI const, std::chrono::duration >&}]::__lambda1(void (CRH::GUI:: )(std::chrono::duration >), CRH::GUI , std ::chrono::duration >)>' typedef typename result_of<_Callable(_Args...)>::type result_type; ^ buildroot-2014.02/output/host/usr/i586-buildroot-linux-uclibc/include/c++/4.8.2/functional:1727:9: error: no type named 'type' in 'class std::result_of)(std::chrono::duration >);
^ buildroot-2014.02/output/host/usr/i586-buildroot-linux-uclibc/include/c++/4.8.2/functional:1727:9: 错误:'class std::result_of 中没有名为'type'的类型)( std::chrono::duration >); Args = {CRH::GUI const, std::chrono::duration >&}]::__lambda1(void (CRH::GUI:: )(std::chrono::duration >), CRH::GUI , std::chrono::duration >)>' _M_invoke(_Index_tuple<_Indices...>)
Args = {CRH::GUI const, std::chrono::duration >&}]::__lambda1(void (CRH::GUI:: )(std::chrono::duration >), CRH::GUI , std ::计时::持续时间>)>' _M_invoke(_Index_tuple<_Indices...>)
It could be a little clearer... but it will be too demanding for GCC.它可能会更清楚一点......但它对 GCC 的要求太高了。
Any idea how to fix this issue?知道如何解决这个问题吗?
Solution解决方案
#include <Types.hpp>
#include <thread>
#include <exception>
#include <functional>
class Thread
{
private:
std::exception_ptr exceptionPtr;
std::thread thread;
public:
using Id = std::thread::id;
using NativeHandleType = std::thread::native_handle_type;
Thread() noexcept = default;
Thread(Thread &&t) noexcept :
exceptionPtr(std::move(t.exceptionPtr)),
thread(std::move(t.thread))
{
}
Thread &operator =(Thread &&t) noexcept
{
exceptionPtr = std::move(t.exceptionPtr);
thread = std::move(t.thread);
return *this;
}
template<typename Callable, typename... Args>
Thread(Callable &&f, Args &&... args) :
exceptionPtr(nullptr),
thread([&](typename std::decay<Callable>::type &&f, typename std::decay<Args>::type &&... args)
{
try
{
std::bind(f, args...)();
}
catch (...)
{
exceptionPtr = std::current_exception();
}
}, std::forward<Callable>(f), std::forward<Args>(args)...)
{
}
bool joinable() const noexcept
{
return thread.joinable();
}
void join()
{
thread.join();
if (exceptionPtr != nullptr)
{
std::rethrow_exception(exceptionPtr);
}
}
void detach()
{
thread.detach();
}
Id getId() const noexcept
{
return thread.get_id();
}
NativeHandleType nativeHandle()
{
return thread.native_handle();
}
static uint32_t hardwareConcurrency() noexcept
{
return std::thread::hardware_concurrency();
}
static void wait(Time t)
{
std::this_thread::sleep_for(t);
}
};
Callable
and Args
are forwarding references, thus template argument deduction can make them either lvalue references or plain types, depending on the value category of argument expressions. Callable
和Args
是转发引用,因此模板参数推导可以使它们成为左值引用或普通类型,具体取决于参数表达式的值类别。
This means that when you reuse the deduced types in the declaration of a lambda:这意味着当您在 lambda 声明中重用推导的类型时:
thread([&](Callable&& f, Args&&... args)
reference collapsing comes into play and, for an lvalue argument refreshDelay
, Args
becomes an lvalue reference.引用折叠开始起作用,对于左值参数
refreshDelay
, Args
成为左值引用。
However, std::thread
stores decayed-copies of the arguments it receives, and then it moves from its internal storage to an actual handler, turning the stored objects into xvalues.然而,
std::thread
存储它接收到的参数的衰减副本,然后它从其内部存储移动到实际的处理程序,将存储的对象转换为 xvalues。 This is what the error tells you: the handler is not callable with the arguments the thread tries to pass in.这就是错误告诉您的内容:无法使用线程尝试传入的参数调用处理程序。
Instead, you can implement it as follows:相反,您可以按如下方式实现它:
template <typename Callable, typename... Args>
Thread(Callable&& f, Args&&... args)
: exceptionPtr(nullptr)
, thread([] (typename std::decay<Callable>::type&& f
, typename std::decay<Args>::type&&... args)
{
// (...)
}
, std::forward<Callable>(f), std::forward<Args>(args)...)
{
// (...)
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.