将右值元组转换为左值元组
Transform a tuple of rvalues into a tuple of lvalues
如果我把整个概念弄错了,我很抱歉,但我正在尝试让一个元组成为实际对象的容器,只有当它被破坏时,这些对象才会超出范围。
我目前有这个:
class MiniThread {
public:
~MiniThread() {
if (m_thread) {
if (m_thread->joinable())
m_thread->join();
delete m_thread;
}
}
void join()
{
if (m_thread == nullptr)
return;
m_thread->join();
m_thread = nullptr;
}
template<typename F, typename... Args>
void run(F func, Args... args)
{
if (m_thread != nullptr)
join();
auto tuple = std::forward_as_tuple(args...);
m_thread = new std::thread([=]() {
__try
{
std::apply(func, tuple);
}
__except (CrashDump::GenerateDump(GetExceptionInformation()))
{
// TODO: log.
exit(1);
}
});
m_started = true;
}
bool started() const { return m_started; }
private:
std::thread *m_thread = nullptr;
bool m_started = false;
};
std::string getString()
{
return std::string("sono");
}
int main()
{
auto test = [&](std::string seila, const std::string& po, std::promise<int>* p)
{
std::cout << seila.c_str() << std::endl;
std::cout << po.c_str() << std::endl;
p->set_value(10);
};
std::promise<int> p;
std::future<int> f;
MiniThread thread;
std::string hello = "hello";
std::string seilapo = "seilapo";
f = p.get_future();
thread.run(test, getString(), "how are you", &p);
thread.join();
int ftest = f.get();
std::cout << ftest << std::endl;
}
到线程 运行 时,args
不再可靠。他们已经被摧毁了。所以我想知道是否有办法在线程的调用中按值复制它们。我已经尝试将可变参数移动到元组中,但是元组总是使用 rvalues
呈现并且仍然失败。
这个:
auto tuple = std::forward_as_tuple(args...);
为 args...
创建一个引用元组 这就是 forward_as_tuple
的工作。然后,您将按值捕获该引用元组:
m_thread = new std::thread([=]{ /* ... */ });
因此,一旦您的论点超出范围,您就只能保留对它们的引用……这会悬空。
但您实际上...根本不需要元组。只需复制参数本身:
m_thread = std::thread([=]() {
func(args...); // func and args, no tuple here
});
也不要写new thread
- thread
已经是句柄类型了,就自己创建一个。
以上复制参数。如果你想 移动 它们,那么在 C++17 中,是的,你需要有一个 tuple
并使用 std::apply
。但不是 forward_as_tuple
...只是 make_tuple
:
m_thread = std::thread([func, args=std::make_tuple(std::move(args)...)]() mutable {
std::apply(func, std::move(args));
});
在C++20中,你不再需要tuple
,可以写一个pack-expansion:
m_thread = std::thread([func, ...args=std::move(args)]() mutable {
func(std::move(args)...);
});
如果我把整个概念弄错了,我很抱歉,但我正在尝试让一个元组成为实际对象的容器,只有当它被破坏时,这些对象才会超出范围。
我目前有这个:
class MiniThread {
public:
~MiniThread() {
if (m_thread) {
if (m_thread->joinable())
m_thread->join();
delete m_thread;
}
}
void join()
{
if (m_thread == nullptr)
return;
m_thread->join();
m_thread = nullptr;
}
template<typename F, typename... Args>
void run(F func, Args... args)
{
if (m_thread != nullptr)
join();
auto tuple = std::forward_as_tuple(args...);
m_thread = new std::thread([=]() {
__try
{
std::apply(func, tuple);
}
__except (CrashDump::GenerateDump(GetExceptionInformation()))
{
// TODO: log.
exit(1);
}
});
m_started = true;
}
bool started() const { return m_started; }
private:
std::thread *m_thread = nullptr;
bool m_started = false;
};
std::string getString()
{
return std::string("sono");
}
int main()
{
auto test = [&](std::string seila, const std::string& po, std::promise<int>* p)
{
std::cout << seila.c_str() << std::endl;
std::cout << po.c_str() << std::endl;
p->set_value(10);
};
std::promise<int> p;
std::future<int> f;
MiniThread thread;
std::string hello = "hello";
std::string seilapo = "seilapo";
f = p.get_future();
thread.run(test, getString(), "how are you", &p);
thread.join();
int ftest = f.get();
std::cout << ftest << std::endl;
}
到线程 运行 时,args
不再可靠。他们已经被摧毁了。所以我想知道是否有办法在线程的调用中按值复制它们。我已经尝试将可变参数移动到元组中,但是元组总是使用 rvalues
呈现并且仍然失败。
这个:
auto tuple = std::forward_as_tuple(args...);
为 args...
创建一个引用元组 这就是 forward_as_tuple
的工作。然后,您将按值捕获该引用元组:
m_thread = new std::thread([=]{ /* ... */ });
因此,一旦您的论点超出范围,您就只能保留对它们的引用……这会悬空。
但您实际上...根本不需要元组。只需复制参数本身:
m_thread = std::thread([=]() {
func(args...); // func and args, no tuple here
});
也不要写new thread
- thread
已经是句柄类型了,就自己创建一个。
以上复制参数。如果你想 移动 它们,那么在 C++17 中,是的,你需要有一个 tuple
并使用 std::apply
。但不是 forward_as_tuple
...只是 make_tuple
:
m_thread = std::thread([func, args=std::make_tuple(std::move(args)...)]() mutable {
std::apply(func, std::move(args));
});
在C++20中,你不再需要tuple
,可以写一个pack-expansion:
m_thread = std::thread([func, ...args=std::move(args)]() mutable {
func(std::move(args)...);
});