如何将可变参数传递给std ::线程?
我想通过从C ++ 11中包装std :: thread类来使用自己的Thread实现,这样我就可以处理像我想要的异常。
这是我的包装类:
#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);
}
};
如果没有参数,它工作得很好:
Thread([&]() { /* do something */ }).detach();
...但如果我尝试传递可变参数:
Thread(&GUI::refreshTask, this, refreshDelay).detach();
...我在编译时遇到一个错误:
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:'std :: thread :: Callable = void(CRH :: GUI ::)(std :: chrono :: :: thread(_Callable &&,_Args && ...)[with _Callable = CRH :: Thread :: Thread(Callable &&,Args && ...)持续时间>); 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:需要从'CRH :: Thread :: Thread(Callable &&,Args && ...)[Callable = void(CRH :: GUI :: )(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'中指定'type'(std :: chrono :: duration>); 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/function:1727:9:error:no'type'in'class std :: result_of)( 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 ...>)
这可能会更清楚一些......但对GCC来说这将过于苛刻。
任何想法如何解决这个问题?
解
#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
和Args
是转发引用,因此根据参数表达式的值类别,模板参数推导可以使它们成为左值引用或简单类型。
这意味着当您在lambda的声明中重用推导类型时:
thread([&](Callable&& f, Args&&... args)
引用折叠起作用,对于左值参数refreshDelay
, Args
成为左值引用。
然而, std::thread
存储它接收到的参数的衰变拷贝,然后它从内部存储器移动到一个实际的处理器,将存储的对象转换为xvalues。 这就是错误告诉你的:处理程序不能用线程试图传入的参数来调用。
相反,您可以按如下方式实施它:
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)...)
{
// (...)
}
链接地址: http://www.djcxy.com/p/30763.html