std::function 是一个类型擦除的类模板,可存储任意符合签名的可调用对象(如lambda、函数指针、bind表达式、仿函数),但不支持重载函数名直接赋值,需注意空状态检查与捕获生命周期。
std::function 是什么类型,能存哪些东西
它是个类型擦除容器,本质是「能装任意符合签名的可调用对象」的通用包装器。不是函数指针,也不是模板别名,而是一个类模板实例化出来的具体类型。
能存
(带捕获或不带捕获)、
表达式、普通函数指针、重载了
的仿函数类实例
不能直接存重载函数名(比如多个
和
),编译器无法推导签名;得显式转型,例如
存储成本比裸函数指针高:通常含一个指针 + 一小段控制块(小对象优化可能避免堆分配),但比
或虚函数调用轻量
怎么声明和赋值,常见编译错误
声明必须写清楚调用签名,比如
—— 括号里是参数列表,前面是返回类型。漏掉
或
就可能匹配失败。
赋值时如果右边类型不匹配,报错信息通常是
或
,而不是“类型不兼容”这种直白提示
捕获局部变量的 lambda 不能赋给
并在作用域外调用——会悬垂引用;要确保捕获的对象生命周期足够长,或者改用值捕获(
)且对象可拷贝
默认可空,构造时不初始化就是空状态,调用前必须检查
,否则触发
性能开销在哪,什么时候该避免用
每次调用都要经过一层间接跳转(类似虚函数),还有小对象优化判断逻辑。对高频路径(比如循环体内每帧调用)有实测影响,尤其在嵌入式或游戏引擎关键路径中。
若只存无捕获 lambda 或函数指针,且签名固定,直接用函数指针(
)或模板参数推导更高效
若需要运行时切换行为但又怕开销,可考虑
配合
,把部分分支转为静态分发
移动语义可用:
支持移动构造/赋值,传参时优先用
避免内部深拷贝(尤其当它内部已分配堆内存时)
和 std::bind、lambda、函数指针的实际选择对比
三者不是替代关系,而是适用场景不同:函数指针最轻但无法捕获;lambda 最灵活但类型唯一、无法直接作为参数类型;
是折中方案,牺牲一点性能换统一接口。
C知道
CSDN推出的一款AI技术问答工具
下载
立即学习
“
C++免费学习笔记(深入)
”;
现在基本被 lambda 取代,除非你要绑定右值引用或做嵌套绑定;但
返回对象可直接赋给
,而某些复杂 lambda(如含模板参数的)可能无法隐式转换
如果你要存的东西生命周期明确、调用频次低(比如事件回调、配置回调),
省心;反之,若追求极致性能或编译期确定性,就绕过它
注意:
不支持 SFINAE 友好检测(比如
可用,但
本身不能参与模板推导约束),写泛型代码时别把它当“万能可调用类型”往 concept 里塞
真正容易被忽略的是空状态处理和捕获生命周期——这两个问题在线上环境爆出来时,往往表现为偶发 crash 或未定义行为,而不是编译报错。
lambdastd::bindoperator()void f(int)void f(double)static_cast(f) std::anystd::function&constno matching constructorcannot convert … to …std::function[=]std::functionif (f)std::bad_function_callvoid(*)(int)std::variant<:function>, std::function<...>>std::visitstd::functionstd::move(f)std::functionstd::bindstd::bindstd::functionstd::functionstd::functionis_invocablestd::function