You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 07:20:33