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

使用std::async传递带显式拷贝构造函数的参数:GCC 11的编译行为是否更合规?

GCC 11的编译行为符合C++标准规范,并非回归问题

先直接给结论:GCC 11拒绝编译这段代码的行为是符合C++标准要求的,之前GCC 10及MSVC允许编译属于实现层面的宽松处理,而非标准规定的正确行为。

核心原因分析

问题的关键在于std::async打包参数的逻辑,以及C++对显式构造函数的转换规则:

  1. std::async会把你传递的函数和参数打包进一个std::tuple,后续在异步执行的上下文里解包并调用目标函数。
  2. 你的struct A的拷贝构造函数被声明为explicit,根据C++标准,显式构造函数不能用于隐式转换场景——而std::async内部打包参数时,需要将临时对象A{}转换为tuple中的A类型成员,这个转换属于隐式转换范畴,因此标准不允许调用显式的拷贝构造函数。

错误信息背后的细节

GCC 11的错误提示could not convert '{...}' from '<brace-enclosed initializer list>' to 'std::tuple<void (*)(const A&), A>',本质是编译器尝试用列表初始化构造tuple,但其中初始化A类型成员时,需要调用显式的拷贝构造函数,这违反了标准中隐式转换不能使用显式构造函数的规则。

GCC 10及之前的libstdc实现可能在打包参数时,通过某种方式绕过了这个限制(比如直接使用显式构造的语法),但GCC 11之后的版本修正了这个实现,严格遵循了C标准的要求。

修复代码的几种方式

如果要让代码在GCC 11+正常编译,可以选择以下方案:

  • 移除A拷贝构造函数的explicit修饰(如果业务逻辑允许);
  • 显式调用拷贝构造函数来生成参数,比如:
    auto f = std::async(std::launch::async, foo, A(A{}));
    
  • 或者使用std::move将临时对象转为右值,显式触发构造调用:
    auto f = std::async(std::launch::async, foo, std::move(A{}));
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.27 18:07:41