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

为何std::function<void(T)>可赋值给std::function<void(T const&)>却不可给std::function<void(T&)>?

std::function参数类型赋值兼容问题解析

先看这段示例代码:

#include <functional>

class Foo {};

int main()
{
    std::function<void(Foo)> func;

    std::function<void(Foo)> f1;
    std::function<void(Foo const&)> f2;
    std::function<void(Foo&)> f3;

    func = f1;
    func = f2;
    func = f3;  // error: no match for ‘operator=’ (operand types are ‘std::function<void(Foo)>’ and ‘std::function<void(Foo&)>’)

    return 0;
}

这段代码中,std::function<void(Foo)>类型的func能正常赋值给同类型的f1,也能赋值给std::function<void(Foo const&)>类型的f2,但赋值给std::function<void(Foo&)>类型的f3时会触发编译错误,核心原因在于std::function的赋值兼容规则是基于调用安全性判断的:

为什么func可以赋值给f2?

func的签名是void(Foo),意味着调用它时需要传入Foo类型的实参(值传递);而f2的签名是void(Foo const&),接受的是Foo的const左值引用。

在C++中,任何Foo类型的对象(包括值传递产生的临时对象)都可以合法绑定到Foo const&引用上:

  • 值传递的实参要么是拷贝后的对象,要么是临时对象,const引用可以延长临时对象的生命周期,且调用过程中不会修改实参,完全符合类型安全要求。
  • 从调用逻辑看,void(Foo)包装的可调用对象,完全能被void(Foo const&)的签名调用——只需要把值实参绑定到const引用即可,没有任何安全风险,因此这种赋值被允许。

为什么func不能赋值给f3?

f3的签名是void(Foo&),需要的是非const左值引用。而func的签名调用时,传入的实参是值类型,会生成临时的Foo对象(右值)。

C++明确禁止临时对象绑定到非const左值引用:

  • 临时对象的生命周期极短,绑定到非const引用后如果对其修改,很可能导致未定义行为;
  • 换句话说,std::function<void(Foo)>包装的可调用对象,无法满足void(Foo&)的调用要求——后者需要一个可修改的左值,而前者只能提供右值,这种调用本身就是非法的,因此std::function的赋值操作直接禁止了这种不兼容的类型转换。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 17:39:54