如何将参数包与函数指针移入结构体?自定义包装packaged_task遇报错
解决自定义ThreadTask中存储带参数函数指针的问题
你的核心问题是没有在BaseFunc中存储调用函数所需的参数,导致Call()里直接调用func()时参数不匹配,触发编译器报错。以下是修正后的实现方案:
修正后的核心代码
#include <memory> #include <tuple> #include <utility> #include <functional> class ThreadTask { struct BaseInterface { virtual void Call() = 0; virtual ~BaseInterface() = default; }; std::unique_ptr<BaseInterface> mImplementation; template <typename F, typename... Args> struct BaseFunc : BaseInterface { F func; std::tuple<Args...> args; // 存储调用函数所需的参数 // 完美转发函数对象和参数,移动构造func,保存参数到tuple BaseFunc(F&& f, Args&&... args) : func(std::move(f)), args(std::forward<Args>(args)...) {} void Call() override { // 展开tuple中的参数,转发给func调用 std::apply([this](auto&&... args) { std::invoke(this->func, std::forward<decltype(args)>(args)...); }, this->args); } }; public: // 对外暴露的构造函数,用于创建ThreadTask实例 template <typename F, typename... Args> ThreadTask(F&& f, Args&&... args) : mImplementation(std::make_unique<BaseFunc<F, Args...>>( std::forward<F>(f), std::forward<Args>(args)...)) {} // 执行任务的接口 void Execute() { if (mImplementation) { mImplementation->Call(); } } };
关键修改点说明
- 存储参数:用
std::tuple<Args...>保存调用函数所需的所有参数,适配任意数量和类型的参数组合。 - 完美转发:构造函数中通过
std::forward转发函数对象和参数,确保移动语义(适配std::packaged_task的移动-only特性),同时避免不必要的拷贝。 - 参数展开调用:使用
std::apply(C++17及以上支持)将tuple中的参数展开,配合std::invoke调用函数对象,确保参数正确转发。
使用示例
#include <future> #include <iostream> int main() { // 包装一个带参数的packaged_task std::packaged_task<int(int, int)> task([](int a, int b) { return a + b; }); std::future<int> fut = task.get_future(); // 创建ThreadTask实例,移动传入task和参数 ThreadTask threadTask(std::move(task), 10, 20); // 在线程中执行任务(这里直接调用模拟线程执行) threadTask.Execute(); // 获取任务结果 std::cout << "Result: " << fut.get() << std::endl; return 0; }
内容的提问来源于stack exchange,提问作者Martin
相关产品推荐
相关产品推荐

