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

std::promise存储const类型在MSVC/GCC/Clang中的实现差异

问题现象

近期使用MSVC编译此前可在GCC、Clang下正常构建的代码时,触发了如下截断的编译错误:

C:/data/msvc/14.33.31424-Pre/include\future(311) error C2678: binary '=': no operator found which takes a left-hand operand of type 'const Result' (or there is no acceptable conversion)
<source>(7): note: could be 'Result &Result::operator =(Result &&)'
<source>(7): note: or       'Result &Result::operator =(const Result &)'

该问题的最小复现代码如下:

#include <future>
#include <iostream>

struct Result {
    int data{0};
};

// 移除const限定即可解决MSVC下的编译问题
using result_t = const Result; 
using promise_result_t = std::promise<result_t>;

auto compute_result(promise_result_t result)
{
    Result some_result{10};
    result.set_value(std::move(some_result));
}

int main()
{
    promise_result_t my_promise;
    auto my_future = my_promise.get_future();
    std::thread thread(compute_result, std::move(my_promise));
    std::cout << "result: " << my_future.get().data;
    thread.join();
    return 0;
}

不同编译器下的编译表现:

  • Clang 11 环境下编译成功
  • GCC 12 环境下编译成功
  • MSVC 19 环境下编译触发报错

原因解析

首先明确核心结论:用const限定类型作为std::promise的模板参数本身不符合C++标准要求,MSVC的报错是严格遵循标准实现的结果,GCC、Clang能编译通过只是实现细节带来的巧合。

  1. 标准层面的约束
    C++标准对std::promise<T>的模板参数有明确要求:T必须是可赋值的具体类型,不能是const限定类型、引用类型、函数类型或抽象类。因为promise内部维护的共享状态需要支持set_value时的值写入操作,const类型天然不支持赋值,本身就不满足promise对类型的要求。
  2. 不同编译器的实现差异
  • MSVC的标准库实现:在共享状态中直接存储T类型的实例对象。调用set_value传入右值时,内部逻辑会对已经存在的T实例调用移动赋值运算符写入新值。当T是const Result时,赋值运算符的左操作数是const类型,无法匹配到可用的赋值重载,就触发了你看到的C2678错误。
  • GCC(使用libstdc++)、Clang(使用libc++)的标准库实现:共享状态不直接存储T对象,而是先分配一块满足对齐要求的原始内存,直到调用set_value时才通过placement new在这块原始内存上直接构造T对象,全程不会调用赋值运算符,只会调用构造函数。构造const类型对象本身是合法的,因此绕开了const类型无法赋值的限制,最终表现为可以正常编译运行。

不要依赖GCC、Clang的这个宽松行为,这种写法本身属于标准未定义行为,随时可能在标准库版本更新后失效。移除std::promise存储类型的const限定,才是符合标准规范的正确解决方案。

内容的提问来源于stack exchange,提问作者Eugene Kuznetsov

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 17:27:33