当前位置: 首页 > news >正文

C++的lambda表达式原理

C++的lambda表达式原理

1 简介

  在 C++11 标准中,引入了 Lambda 表达式这一重要特性,为开发者提供了更简洁、灵活的编程方式。Lambda 表达式,也被称为匿名函数,允许在代码中直接定义一个可调用的代码单元,而无需显式地定义一个命名函数。这一特性极大地增强了 C++ 的表达能力,尤其在函数式编程和算法应用中发挥了重要作用。本文将深入探讨 C++ Lambda 表达式的语法、特性、应用场景以及其背后的实现原理。

  ambda 表达式可以理解为一个匿名的内联函数,它具有一个返回类型、一个参数列表和一个函数体。与普通函数不同的是,Lambda 表达式通常使用尾置返回类型。其基本语法形式如下:

[capture list](parameter list) -> return type { function body }
  • capture list:捕获列表,用于指定 Lambda 表达式所在函数中定义的局部变量列表,这些变量可以在 Lambda 表达式内部使用。​捕获可以进行值捕获,引用捕获,可变捕获,以及前几种的混合捕获。
  • parameter list:参数列表,与普通函数的参数列表类似,用于接收调用时传递的参数。​
  • return type:返回类型,指定 Lambda 表达式的返回值类型。在某些情况下,编译器可以自动推断返回类型,此时可以省略该部分。​
  • function body:函数体,包含了 Lambda 表达式实际执行的代码逻辑。
std::vector<int> numbers = {5, 2, 8, 1, 9};
std::sort(numbers.begin(), numbers.end(), [](int a, int b) { return a < b; });
for (int num : numbers) {std::cout << num << " "; // 输出:1 2 5 8 9
}

2 原理

  当编写一个 Lambda 表达式时,编译器会将其转换为一个未命名类的未命名对象,这个类重载了函数调用运算符operator()。例如,考虑以下 Lambda 表达式:

int main(){auto lambda = [](int a, int b) { return a + b; };lambda(1,2);
}

  编译器大致会将其转换为类似如下的代码。可以看到主要就是创建了一个匿名类并且重载类对应的operator()函数,同时重载operator*__invoke函数提供了一种方式,使得 lambda 表达式可以被转换为函数指针类型。这对于需要将 lambda 作为参数传递给接受函数指针的函数非常重要。例如,某些标准库函数或算法可能需要一个函数指针作为参数。

int main()
{class __lambda_3_19{public: inline /*constexpr */ int operator()(int a, int b) const{return a + b;}using retType_3_19 = int (*)(int, int);inline constexpr operator retType_3_19 () const noexcept{return __invoke;};private: static inline /*constexpr */ int __invoke(int a, int b){return __lambda_3_19{}.operator()(a, b);}};__lambda_3_19 lambda = __lambda_3_19{};lambda.operator()(1, 2);return 0;
}

值捕获
编译器会为捕获的变量在匿名类中创建相应的数据成员,并在构造函数中使用捕获变量的值进行初始化。例如:

int main(){int a = 1;int b = 2;auto lambda = [=]() { return a + b; };lambda();
}

  对应生成的代码中添加了两个成员,并且在匿名类初始化时初始化这两个成员。

int main()
{int a = 1;int b = 2;class __lambda_5_19{public: inline /*constexpr */ int operator()() const{return a + b;}private: int a;int b;public:__lambda_5_19(int & _a, int & _b): a{_a}, b{_b}{}};__lambda_5_19 lambda = __lambda_5_19{a, b};lambda.operator()();return 0;
}

引用捕获
引用捕获同理,区别是成员变成了引用。

int main(){int a = 1;int b = 2;auto lambda = [&]() { return a + b; };lambda();
}
int main()
{int a = 1;int b = 2;class __lambda_5_19{public: inline /*constexpr */ int operator()() const{return a + b;}private: int & a;int & b;public:__lambda_5_19(int & _a, int & _b): a{_a}, b{_b}{}};__lambda_5_19 lambda = __lambda_5_19{a, b};lambda.operator()();return 0;
}

3 使用lambda需要注意的点

  使用lambda时需要注意

  1. 捕获的变量的生命周期,捕获的变量在 lambda 执行时必须有效。如果 lambda 的生命周期超过了捕获变量的有效性,将导致未定义行为。
  2. 尽管 lambda 通常是轻量级的,但如果捕获的变量较多或较复杂,可能会导致额外的内存开销。在性能关键的场景中,要注意这一点。
http://www.dtcms.com/a/292939.html

相关文章:

  • 【RK3576】【Android14】MIC开发调试
  • 【iOS】SideTable
  • [学习] 笛卡尔坐标系的任意移动与旋转详解
  • 交叉编译opencv(Cpp)于arm64架构开发板上
  • AI 音频产品开发模板及流程(二)
  • 使用python中的pymysql库,并且转化为数组元组数据
  • 【多任务YOLO】A-YOLOM
  • 字体识别实战:用Python打造智能字体侦探工具
  • for-of和for-in
  • 2025年07月22日Github流行趋势
  • Day20-二叉树基础知识
  • python flusk 监控
  • 行业分类表sql
  • 深入解析 Spark:关键问题与答案汇总
  • 力扣刷题 -- 572.另一颗树的子树
  • 逻辑回归全景解析:从数学本质到工业级优化
  • docker 设置镜像仓库代理
  • 企业微信会议室智能预约实战:从线上预约到无钥匙开门
  • 企业微信快捷回复设定方法(提高效率)
  • 数据库事务 ACID
  • 洛谷 单词方阵 dfs
  • 免费实验室记录本:生物医药科研的数字化转型基石
  • Docker,其他机器下载镜像并copy到目标机器导入docker镜像
  • LWIP学习记录2——MAC内核
  • 合同管理系统技术架构深度解析:快鹭云如何通过NLP+区块链实现纠纷率下降67%|附动态安全库存算法实现
  • NumPy:Python 科学计算的基石
  • 分类模型(BERT)训练全流程
  • IO复用(多路转接)
  • c语言学习(days08)
  • 对比学习 | 软标签损失计算