C++右值转发至线程再转至函数的编译错误问题求助
问题描述
我试图创建一个deadline类,其构造函数会启动线程,当线程内的截止时间(时间段)到达时执行传入的函数。该类构造函数接收目标函数及其参数作为入参,支持按值或引用传递参数,但使用std::move传递右值参数时会出现编译错误,传递const右值(如字符串字面量)则可正常运行,求解决方法。
附代码示例:
#include <thread> #include <atomic> #include <future> #include <iostream> #include <iomanip> namespace { std::atomic<bool> running{true}; template <typename Period> using duration = std::chrono::duration<int64_t, Period>; template <typename PromiseType = void> class deadline { std::promise<PromiseType> stopper_{}; std::thread thread_{}; public: deadline() = delete; template <typename Period, typename Function, typename... Args> explicit deadline(const duration<Period> &interval, Function&& func, Args&&... args) noexcept { if (interval.count() > 0) { std::future<PromiseType> future{ stopper_.get_future() }; using tuple = std::tuple<std::decay_t<Args>...>; auto decay_copied = std::make_unique<tuple>(std::forward<Args>(args)...); thread_ = std::thread( [](std::future<PromiseType>&& future, const duration<Period> &interval, Function&& func, decltype(decay_copied)&& params) { if (future.wait_for(interval) == std::future_status::timeout) { std::apply(func, *params); } }, std::move(future), std::cref(interval), std::forward<Function>(func), std::move(decay_copied)); } } deadline(const deadline&) = delete; deadline(deadline&&) = delete; deadline& operator=(const deadline&) = delete; deadline& operator=(deadline&&) = delete; ~deadline() { stopper_.set_value(); if (thread_.joinable()) { thread_.join(); } } }; } auto main() -> int { std::string test1{"test 1"}; std::string test2{"test 2"}; std::string test3{"test 3"}; std::string test4{"test 4"}; using namespace std::chrono_literals; deadline dl(5s, []( std::string test_1 , const std::string& test_2 , std::string& test_3 , std::string&& test_4 ) { std::cout << test_1 << '\n'; std::cout << test_2 << '\n'; std::cout << test_3 << '\n'; test_3 += " modified"; std::cout << test_4 << '\n'; running = false; } , test1 , std::cref(test2) , std::ref(test3) , std::move(test4) //, "test 4" ); while (running.load()) { std::this_thread::sleep_for(std::chrono::milliseconds(500)); } std::cout << test1 << '\n'; std::cout << test2 << '\n'; std::cout << test3 << '\n'; std::cout << test4 << '\n'; return 0; }
解决方案
编译错误的核心原因:用std::decay_t<Args>处理std::move(test4)时,decay_t会将右值引用std::string&&衰减为std::string,tuple中存储的是普通std::string对象;但回调函数最后一个参数是std::string&&,std::apply默认会将tuple元素作为左值传递,无法匹配右值引用参数,导致编译失败。
修复方法:在std::apply时转发tuple元素的右值语义
修改线程内的std::apply调用,用std::move将tuple中的元素按原始值类别转发,让右值参数能匹配回调的右值引用参数:
std::apply(func, std::move(*params));
修复后的关键代码片段:
thread_ = std::thread( [](std::future<PromiseType>&& future, const duration<Period> &interval, Function&& func, decltype(decay_copied)&& params) { if (future.wait_for(interval) == std::future_status::timeout) { // 用std::move转发tuple元素,保留右值语义 std::apply(func, std::move(*params)); } }, std::move(future), std::cref(interval), std::forward<Function>(func), std::move(decay_copied));
此修复既保留了原有的参数生命周期管理逻辑(用std::make_unique存储decay后的tuple),又能正确处理右值参数的传递,同时其他参数的引用/值传递语义不受影响。
内容的提问来源于stack exchange,提问作者user2749702
相关产品推荐
相关产品推荐

