C++中lambda表达式(匿名函数)
C++中lambda表达式(匿名函数)
1.1 背景交代
下面代码是我读取kitti stereo2012数据集的主函数代码,这部分代码运行后,自动播放所有数据集
#include <io/kitti_dataset.h>
#include <opencv2/highgui.hpp>
int main() {
//解析配置
std::string config_file = "~/Documents/CppProjects/vslam_ws/config/kittistereo.yaml";
//初始化数据集
KittiDataset dataset(config_file);//path -> config -> kitti -> private var
//初始化左右图像、相机、当前帧下标
cv::Mat left, right;
StereoCamera cam;
int frame_id = 0;
//读取数据帧
while (dataset.NextStereo(left,right,cam)) {
//显示加载的数据
std::cout << "Frame: " << frame_id++
<< " | Baseline: " << cam.baseline << "m" << std::endl;
cv::Mat stereo;
cv::hconcat(left, right, stereo);
cv::imshow("Stereo", stereo);
if (cv::waitKey(10) == 27) break;
}
return 0;
}


现在我想使用键盘n播放下一组,键盘b返回上一组的功能
于是AI给出了代码
#include <io/kitti_dataset.h>
#include <opencv2/highgui.hpp>
int main() {
//解析配置
std::string config_file = "~/Documents/CppProjects/vslam_ws/config/kittistereo.yaml";
// 按索引加载指定帧(通过重建数据集前进到 idx)
auto load_frame = [&](int idx, cv::Mat& left, cv::Mat& right, StereoCamera& cam)->bool {
KittiDataset ds(config_file);
cv::Mat l, r;
StereoCamera c;
for (int i = 0; i <= idx; ++i) {
if (!ds.NextStereo(l, r, c)) return false;
}
left = l; right = r; cam = c;
return true;
};
// 初始化
cv::Mat left, right;
StereoCamera cam;
int cur = 0;
if (!load_frame(cur, left, right, cam)) return 0;
// 交互浏览:n 下一组,b 上一组,ESC/q 退出
while (true) {
std::cout << "Frame: " << cur
<< " | Baseline: " << cam.baseline << "m" << std::endl;
cv::Mat stereo;
cv::hconcat(left, right, stereo);
cv::imshow("Stereo", stereo);
int key = cv::waitKey(0);
if (key == 27 || key == 'q' || key == 'Q') break; // ESC or q
if (key == 'n' || key == 'N') {
if (load_frame(cur + 1, left, right, cam)) {
++cur;
} else {
std::cout << "已到最后一帧" << std::endl;
}
} else if (key == 'b' || key == 'B') {
if (cur > 0 && load_frame(cur - 1, left, right, cam)) {
--cur;
} else {
std::cout << "已到第一帧" << std::endl;
}
}
}
return 0;
}
1.2 什么是 Lambda 表达式?
Lambda 表达式(Lambda Expression) 是一种 **定义匿名函数(没有名字的函数)**的语法。你可以把它理解成 “写在一行的临时函数”,不需要单独声明或定义,就能直接使用
基本语法如下:
[capture](parameters) -> return_type {
function_body;
};

1.3 为什么需要 Lambda?
在写 C++ 时,经常会遇到这种情况:
“我想临时定义一个小功能(比如计算、排序规则、回调函数),但是这个功能只在当前函数里用一次,没必要定义成独立函数。”
以前:
bool compare(const Item& a, const Item& b)
{
return a.value < b.value;
}
std::sort(v.begin(), v.end(), compare);
现在用 Lambda:
std::sort(v.begin(), v.end(), [](const Item& a, const Item& b) {
return a.value < b.value;
});
捕获列表详解
Lambda 通过 [capture] 告诉编译器:
“我要把这些外部变量带进我的小函数里一起用。”
Lambda 可以“捕获”当前作用域里的变量,用三种常见方式:
捕获只对 外部变量 有意义;
Lambda 内部定义的变量和普通函数变量一样。
例如:
int main() {
std::string config_file = "...";
auto load_frame = [&](int idx, cv::Mat& left, cv::Mat& right, StereoCamera& cam)->bool {
KittiDataset ds(config_file); // ✅ 捕获了匿名函数当前所在作用域中的局部变量 config_file
...
};
}
“当前作用域” 就是整个 main() 函数体;
config_file 是定义在 main() 里的局部变量;
[&] 表示以引用方式捕获当前作用域中能看到的所有变量;
所以 config_file 可以在 Lambda 内直接使用。
也就是说lambda表达式(匿名函数)所在作用域中的所有局部变量,使得在匿名函数内部可以使用这些局部变量
捕获语法
(1)如果不想在匿名函数内部修改当前作用域局部变量的话,就使用值捕获[=]
(2)如果想在匿名函数内部修改当前作用域局部变量的话,就使用引用捕获[&]
(3)如果在匿名函数内部,有的捕获变量想改变,有的捕获变量不想改变,就使用[a,&b]

1.4 回到背景提到的例子
重点看一下load_frame这个lambda表达式
// 按索引加载指定帧(通过重建数据集前进到 idx)
auto load_frame = [&](int idx, cv::Mat& left, cv::Mat& right, StereoCamera& cam)->bool {
KittiDataset ds(config_file);
cv::Mat l, r;
StereoCamera c;
for (int i = 0; i <= idx; ++i) {
if (!ds.NextStereo(l, r, c)) return false;
}
left = l; right = r; cam = c;
return true;
};

实际上这段 Lambda 完全可以改写为一个普通函数:
bool load_frame(int idx, cv::Mat& left, cv::Mat& right, StereoCamera& cam, const std::string& config_file) {
KittiDataset ds(config_file);
cv::Mat l, r;
StereoCamera c;
for (int i = 0; i <= idx; ++i) {
if (!ds.NextStereo(l, r, c)) return false;
}
left = l; right = r; cam = c;
return true;
}
不过这样就必须把 config_file 显式传进去。而 Lambda 通过 [&] 直接引用了它,使得调用更简洁。
1.5 什么时候使用 Lambda?

更多推荐


所有评论(0)