如何利用std::promise和std::future在线程间传递含std::promise<自身>的结构体?
解决包含
std::promise<自身类型>的结构体编译错误及线程通信问题 错误原因
你遇到的编译错误static assertion failed: template argument must be a complete class or an unbounded array,本质是**std::promise<T>要求模板参数T必须是完整类型**,但在定义struct test时,声明std::promise<test> p;的那一刻,test结构体还没完成完整定义(编译器还没读到结构体的结束符号}),因此触发了静态断言失败。
另外还有隐藏问题:std::promise是不可拷贝的类型,你的代码里虽然用了std::move转移promise所有权,但后续set_value(t)尝试拷贝整个test对象(包含promise成员)时,会因为promise不可拷贝而报错。
解决方案
方案一:用智能指针包装std::promise
通过std::unique_ptr包装std::promise<test>,指针类型的声明不要求指向的类型是完整的,从而绕过类型不完整的限制,同时利用智能指针的移动语义避免拷贝问题。
修改后的代码:
#include <iostream> #include <future> #include <thread> #include <memory> struct test{ std::unique_ptr<std::promise<test>> p; int val; }; void setVal(test &t){ t.val = 1; // 移动构造test对象,避免拷贝不可拷贝的成员 t.p->set_value(std::move(t)); } int main(){ test t; auto p = std::make_unique<std::promise<test>>(); std::future<test> f = p->get_future(); t.p = std::move(p); std::thread t1(setVal, std::ref(t)); t1.join(); std::cout << f.get().val << std::endl; return 0; }
方案二:将std::promise移出结构体(更贴合你的原始需求)
你的核心需求是:结构体包含执行函数、结果存储,通过promise将处理后的结构体传回主线程。完全可以把promise从结构体中剥离,作为线程函数的参数传递,这样既避免了类型不完整问题,也让结构体职责更清晰。
贴合你原始需求(包含std::function和std::any)的代码:
#include <iostream> #include <future> #include <thread> #include <functional> #include <any> struct Task { std::function<std::any()> toExecute; std::any result; }; void executeTask(Task& task, std::promise<Task>&& p) { // 执行函数并赋值结果 task.result = task.toExecute(); // 移动传递task对象给promise p.set_value(std::move(task)); } int main() { Task t; // 定义要执行的函数,返回值存入std::any t.toExecute = []() -> std::any { return 123; }; std::promise<Task> p; std::future<Task> f = p.get_future(); // 启动子线程,传递task引用和promise的所有权 std::thread t1(executeTask, std::ref(t), std::move(p)); t1.join(); // 从future中获取结果并解析 auto finalResult = std::any_cast<int>(f.get().result); std::cout << "执行结果:" << finalResult << std::endl; return 0; }
关键说明
std::promise和std::future的模板参数必须是完整类型,这是C++标准对这类模板的要求,目的是确保模板能正确处理类型的构造、析构等操作。- 包含不可拷贝成员(如
std::promise、std::unique_ptr)的类,只能通过移动语义传递,不能直接拷贝。
内容的提问来源于stack exchange,提问作者Aerin
相关产品推荐
相关产品推荐

