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

如何利用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 20:13:18