c++ - 将一个右值的元组转换为一个左值的元组

标签 c++ tuples c++17 variadic-templates

很抱歉,如果我把整个概念弄错了,但是我正在尝试将实际对象的容器做成一个元组,在这些对象中,只有销毁它们,这些对象才会超出范围。

我目前有这个:

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)...);
});

关于c++ - 将一个右值的元组转换为一个左值的元组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61236186/

相关文章:

c++ - GNUMakefile 和 gcc : resolving the order of conflicting "-std=c++" requirements

c++ - 为什么 `iota(0) | take(0)` 不是 C++20 中的模型 range::sized_range?

c++ - 在 C++ 中得到错误的答案

c++ - Facebook 编程挑战

python - 如何更改列表元组中的第一个值?

python - 如何扩展元组项作为参数 os 系统调用?

powershell - Powershell 中带有元组键的字典

for 与 while 循环中的 C++ 迭代器行为

c++ - 即使在使用 skip_permission_denied 时,std::filesystem 递归迭代器也会抛出 permission_denied

c++ - C++21 是下一个标准吗?