如何将可变参数传递给std::线程
How to pass variadic args to a std::thread?
我想通过包装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-uclbc/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:buildroot-2014.02/output/host/usr/i586 buildroot-linux-uclbc/include/c++/4.8.2/thread:137:47:必需自"std::thread::thread(_Callable&&,_Args&…)"[其中_Callable=CRH::thread::thread(可调用&&,Args&…)[其中Callable=void(CRH::GUI::)(std::chrono::duration>);Args={CRH:;GUIconst,std::chrono::持续时间>&}]::__lambda1_Args={void(CRH::GUI::&)(std::chrono::duration>),CRH:;GUI:常量&,std::chrono::持续时间>&}/home/cyrl/Documents/crh-2016/src/robot2//core/Thread.hp:72:30:从"CRH::Thread::Thread(Callable&&,Args&…)[带有Callable=void(CRH:;GUI::)(std::chrono::duration>);Args={CRH:src/core/GUI.cpp:90:57:此处需要buildroot-2014.02/output/host/usr/i586 buildroot-linux-uclbc/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:typedef typename result_of<_可调用(_Args…)>::type result_type;^buildroot-2014.02/output/host/usr/i586 buildroot-linux-uclbc/include/c++/4.8.2/functional:11727:9:error:'classstd::result_of)中没有名为'type'的类型(std::chrono::duration>);Args={CRH::GUI const,std::chrono::duration>&}]::__lambda1(void(CRH:;GUI::)(std::chrono::duration>),CRH::GUI,std:_M_invoke(_Index_tuple<_Indices…>)
它可能会更清楚一点。。。但这对海湾合作委员会来说要求太高了。
知道如何解决这个问题吗?
解决方案
#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
存储它接收的参数的衰变副本,然后它从内部存储移动到实际的处理程序,将存储的对象转换为x值。这就是错误告诉你的:线程试图传入的参数不能调用处理程序
相反,您可以按如下方式实现它:
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)...)
{
// (...)
}
- 将参数打包的参数传递到 std::queue 中,以便稍后使用不同的函数调用
- 为什么我不能将引用作为 std::async 的函数参数传递
- 将 std::type_index 作为模板参数传递给函数模板
- 使用std::move将std::unique_ptr作为qt信号参数传递
- 如何将 std::cin 作为函数的参数传递?
- 使用 std::move 将参数传递给函数,如果该参数声明为按值传递或使用移动操作数 &&,是否有区别?
- 将 std::function* 传递给模板参数
- 将双指针作为参数传递给需要引用 std::vector <double>的函数
- 如何将 std::string 作为构造函数参数传递,并将其保存的 C 字符串存储在 void 指针中?
- 将参数传递给成员函数,就像使用 std::cout 一样
- 有什么理由C++ 11+ std::mutex 应该声明为全局变量,而不是作为函数参数传递到 std::thread 中
- 类模板的参数太少 "std::pair":在函数中将 std 对作为参数传递
- 如何将函数及其参数传递给成员函数内的 std::async
- 将 istream 转换为 ifstream 时将 std::cin 传递到参数时出现问题
- 将 std::ofstream 对象作为参数传递给类方法
- 我如何将std ::数组作为模板参数传递,其中C 中的元素数量不同
- 是否可以将 std::d eque 的成员函数作为参数传递?
- 使用作为参数传递的 std::intializer_list 初始化 std::数组
- 无法将 std::time_get.get_date 函数作为参数传递给另一个函数
- 从作为模板函数参数传递的 std::function 推导返回和参数类型