gpt4 book ai didi

c++ - 如何将可变参数传递给 std::thread?

转载 作者:塔克拉玛干 更新时间:2023-11-03 01:51:51 25 4
gpt4 key购买 nike

我想通过包装 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: In instantiation of '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; _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 = {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 >&}]::__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 >); 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);
}
};

最佳答案

CallableArgs 是转发引用,因此模板参数推导可以使它们成为左值引用或普通类型,具体取决于参数表达式的值类别。

这意味着当您在 lambda 声明中重用推导的类型时:

thread([&](Callable&& f, Args&&... args)

引用折叠开始发挥作用,对于左值参数 refreshDelayArgs 成为左值引用。

然而,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)...)
{
// (...)
}

关于c++ - 如何将可变参数传递给 std::thread?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34731367/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com