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

C++中能否实现与原函数参数行为一致的零开销函数包装器?

问题解答

核心行为对比

首先看原始函数及直接调用的行为:

void Test(Object obj){}

直接调用时三种传参的不同表现:

Object a;
Test(Object{});     // 传入prvalue,C++17起可通过拷贝消除直接在形参位置构造,无额外拷贝/移动
Test(a);            // 传入左值,触发拷贝构造函数
Test(std::move(a)); // 传入xvalue,触发移动构造函数

但使用函数包装器(如std::invoke)时,无法复刻Test(Object{})的零开销:

std::invoke(Test, Object{}); // prvalue会被物化为临时对象,额外触发一次移动构造
std::invoke(Test, a);            // 行为与直接调用一致,触发拷贝构造
std::invoke(Test, std::move(a)); // 行为与直接调用一致,触发移动构造

无法实现零开销包装的本质原因

  • 若包装器使用完美转发(通过引用绑定参数):prvalue被绑定到引用时必须完成物化,生成临时对象,之后传递给按值形参只能通过移动/拷贝初始化,无法跳过临时对象直接构造形参。
  • 若包装器按值接收参数:传入的prvalue会先构造包装器的参数(变为左值),再传递给目标函数时会触发额外的拷贝,开销更大。

两种方案都无法达成直接调用时的拷贝消除效果。

相关改进进展

这个问题已被C++标准社区关注,有针对性的提案试图解决:

  • P0847R7 "Forwarding References for Parameters":该提案已纳入C++23标准,允许包装器将prvalue直接转发给按值参数,避免临时对象物化带来的移动开销,让编译器可以进行拷贝消除。目前部分主流编译器已经开始支持该特性。
  • 其他相关提案如P1065R3也从prvalue优化的角度,间接减少这类场景下的不必要构造。

在编译器完全支持C++23的相关特性前,仍无法实现完全等价于直接调用的零开销函数包装器。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 10:37:00