lambda可作为函数参数传递,但必须用std::function或模板参数接收;无捕获的才能隐式转函数指针,带捕获的只能用std::function(类型擦除、签名匹配)或模板(零开销、编译期推导)。

能传,但方式选错会编译失败或隐式拷贝开销大;最稳妥的是用 std::function,性能敏感场景可考虑模板参数。
用 std::function 接收 Lambda 最通用
这是最直接、兼容性最好的方式,适用于所有可调用对象(Lambda、函数指针、functor)。它把类型擦除,只关心签名是否匹配。
- 必须包含头文件
<functional></functional> - 声明时需明确写出调用签名,例如
std::function<bool int></bool>,不能只写std::function<auto></auto> - 每次传参都会发生一次小对象拷贝(内部有约 24 字节的存储缓冲),对极高频调用(如每帧上万次)可能有影响
- 支持捕获变量的 Lambda(包括
[=]、[&]、[this]),无需额外处理
示例:
#include <vector>
#include <functional>
#include <algorithm>
void process(std::vector<int>& v, std::function<bool int> cmp) {
std::sort(v.begin(), v.end(), cmp);
}
// 调用
std::vector<int> data = {3, 1, 4};
process(data, [](int a, int b) { return a
<h3>用模板参数接收 Lambda 避免运行时开销</h3>
<p>当 Lambda 是临时、一次性使用的(比如算法回调),模板推导能完全避免 <code>std::function</code> 的类型擦除成本,且支持 <code>constexpr</code> 场景。</p><div class="aritcle_card flexRow artxards">
<div class="artcardd flexRow">
<a class="aritcle_card_img" rel="nofollow" href="/xiazai/gongju/2823" title="C++14"><img
src="https://img.php.cn/upload/manual/001/431/639/6ac8b33c327c4749.png" alt="C++14" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
<div class="aritcle_card_info flexColumn">
<a rel="nofollow" href="/xiazai/gongju/2823" title="C++14" class="overflowclass">C++14</a>
<p class="overflowclass">C++14 对 C++11 的修正与增强版本,适合旧系统维护和较老工具链兼容。</p>
</div>
<a rel="nofollow" href="/xiazai/gongju/2823" title="C++14" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span>
</a>
</div>
</div>
<ul>
<li>函数定义需是模板:例如 <code>template <typename compare> void process(..., Compare&& cmp)</typename></code>
</li>
<li>完美转发推荐用右值引用 <code>Compare&&</code> + <code>std::forward<compare>(cmp)</compare></code>,避免不必要的拷贝</li>
<li>不支持直接传入函数指针(除非显式转换),也不方便存为成员变量或跨函数传递</li>
<li>如果 Lambda 捕获了局部变量,而你试图把它存进类成员再 later 调用,模板方式会失败——因为类型是 unique 的,无法命名和保存</li>
</ul>
<p>示例:</p>
<pre class="brush:php;toolbar:false;">template <typename compare>
void process_opt(std::vector<int>& v, Compare&& cmp) {
std::sort(v.begin(), v.end(), std::forward<compare>(cmp));
}
process_opt(data, [](int a, int b) { return a > b; }); // 升序变降序,零开销
</compare></int></typename>
传带捕获的 Lambda 时要注意生命周期
捕获列表决定 Lambda 是否安全:按引用捕获([&x] 或 [&])的变量一旦离开作用域,Lambda 再调用就会 UB。
- 若 Lambda 可能被保存、异步执行或延迟调用,一律改用值捕获(
[x]或[=]) -
[=]捕获的是副本,但如果捕获的是指针或智能指针,仍要确保所指对象生命周期足够长 - 类成员函数中写 Lambda 并捕获
this,要确认该 Lambda 不会在对象析构后被调用 - 不要在返回的 Lambda 中捕获局部数组或栈变量的引用
为什么不能直接用函数指针类型?
只有无捕获的 Lambda(即 [](...) { ... })才能隐式转为函数指针;一旦用了 [x]、[&] 或 [this],就不再是“普通函数”,没有对应函数指针类型。
- 错误写法:
void f(bool(*)(int, int))→ 传[x](int a, int b){...}会编译失败 - 即使编译通过(比如传了个空捕获 Lambda),后续若想扩展逻辑加捕获,就得改接口,不灵活
- 函数指针无法体现调用约定(如
__stdcall),跨平台也更脆弱
真正需要函数指针的极少数场景(如 C API 回调),得先用 std::function 封装,再借助 std::bind 或静态桥接函数中转——但这已不属于“直接传 Lambda”的范畴。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










