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

C++lambda函数

什么是lambda函数

文章目录

  • 什么是lambda函数
  • 为什么需要lambda
  • lambda的完整语法结构
  • lambda的实现原理
  • C++14/17/20 中的新特性

简单来说, Lambda 函数是一个“就地”定义、“当场”使用的匿名函数。
想象一下,你只是需要一个简单的函数来作为另一个函数的参数(例如,给 std::sort 提供一个排序规则),但你又不想在别处郑重其事地定义一个完整的、有名字的函数。这时,Lambda 就是你的最佳选择。它让你可以在需要的地方直接写出函数体,非常方便和简洁。

为什么需要lambda

我们通过一个例子来看看 Lambda 的威力。假设你有一个 std::vector<int>,想对它进行自定义排序,规则是:偶数在前,奇数在后。

在不使用lambda的时候
你可能需要定义一个独立的函数或者一个函数对象。

// 方法一:定义一个普通函数
bool compareForSort(int a, int b) {bool a_is_even = (a % 2 == 0);bool b_is_even = (b % 2 == 0);if (a_is_even != b_is_even) {return a_is_even; // 如果一个偶一个奇,偶数排前面}return a < b; // 如果同为偶数或奇数,按升序排
}// ... 在 main 函数中 ...
std::vector<int> v = {1, 2, 3, 4, 5, 6};
std::sort(v.begin(), v.end(), compareForSort);

这个 compareForSort 函数可能只在这里用一次,却需要定义在全局或类作用域中,显得有些“笨重”。

使用lambda的时候

#include <iostream>
#include <vector>
#include <algorithm>
int main() {std::vector<int> v = {1, 2, 3, 4, 5, 6};// 直接在 std::sort 的第三个参数位置定义 Lambda 函数std::sort(v.begin(), v.end(), [](int a, int b) {bool a_is_even = (a % 2 == 0);bool b_is_even = (b % 2 == 0);if (a_is_even != b_is_even) {return a_is_even;}return a < b;});for (int n : v) {std::cout << n << " "; // 输出: 2 4 6 1 3 5}std::cout << std::endl;return 0;
}

优点显而易见:

  • 代码更紧凑: 函数逻辑直接写在了调用的地方,可读性更高。
  • 上下文关联性强: 排序的规则和排序的动作紧密地放在一起,一目了然。
  • 避免命名污染: 无需为只用一次的简单功能函数想一个名字。

lambda的完整语法结构

lambda 的语法可能初看起来有些奇怪,但一旦掌握,就会觉得非常强大。

[capture](parameters) specifiers -> return_type { function_body }

我们来逐一分解:

  1. [] - 捕获列表
    这是 Lambda 最核心、最强大的部分。它决定了 Lambda 函数可以访问其定义时所在作用域中的哪些变量。
    • []:不捕获任何外部变量
    • [=]按值捕获所有外部变量。在 Lambda 函数体内,这些变量是只读的副本(除非使用 mutable)。
    • [&]按引用捕获所有外部变量。在 Lambda 函数体内,可以修改这些外部变量。
    • [x, &y]:指定捕获列表。x 按值捕获,y 按引用捕获。
    • [=, &y]:除了 y 按引用捕获,其他所有变量都按值捕获。
    • [&, x]:除了 x 按值捕获,其他所有变量都按引用捕获
    • [this]:捕获当前类对象的 this 指针,这样就可以在 Lambda 内部访问类的成员变量和成员函数。
      示例:
int x = 10;
int y = 20;// 按值捕获 x
auto lambda1 = [x]() { std::cout << "x = " << x << std::endl; };
lambda1(); // 输出 x = 10// 按引用捕获 y
auto lambda2 = [&y]() { y = 30; };
lambda2();
std::cout << "y = " << y << std::endl; // 输出 y = 30,y 的值被改变了// 混合捕获
auto lambda3 = [x, &y]() {// x++; // 错误!按值捕获的变量是 const 的y++;
};
lambda3();
std::cout << "y after lambda3 = " << y << std::endl; // 输出 y after lambda3 = 31
  1. () - 参数列表
    和普通函数的参数列表一样。如果你的 Lambda 不需要参数,可以省略括号 ()
  2. specifiers - 可选说明符
    这里可以放一些关键字,最常用的是 mutable
    • mutable: 允许你在 Lambda 函数内部修改按值捕获的变量。这个修改只在 Lambda 内部有效,不会影响外部原始变量。
int a = 0;
auto lambda_mutable = [a]() mutable {a = 5; // 如果没有 mutable,这行会编译错误std::cout << "Inside lambda, a = " << a << std::endl;
};
lambda_mutable(); // 输出: Inside lambda, a = 5
std::cout << "Outside lambda, a = " << a << std::endl; // 输出: Outside lambda, a = 0   
  1. -> return_type - 返回类型
    指定 Lambda 函数的返回类型。在大多数情况下,编译器可以根据 return 语句自动推断出返回类型,所以这个部分通常可以省略
    只有在少数复杂情况下(例如函数体中有多个返回语句,且返回类型不同)才需要显式指定。
  2. {} - 函数体
    和普通函数一样,这里是 Lambda 函数的具体实现逻辑。

lambda的实现原理

在底层,编译器会为每个 Lambda 表达式生成一个唯一的、匿名的类。这个类重载了 operator()(函数调用运算符),使得其实例可以像函数一样被调用。
这个生成的类被称为闭包

  • 你定义的 Lambda 函数体,成为了这个类 operator() 方法的函数体。
  • 你捕获的变量,成为了这个类的成员变量。
    • 按值捕获的变量被拷贝到成员变量中。
    • 按引用捕获的变量则作为引用成员
      这就是为什么 Lambda 可以“记住”其创建时环境的原因

C++14/17/20 中的新特性

lambda 也在不断进化,变得越来越强大:

  • 泛型 lambda (C++14): 可以使用 auto 关键字作为参数类型,让 lambda 像模板一样工作。
 auto generic_add = [](auto a, auto b) {return a + b;
};
int sum_int = generic_add(3, 4);       // 7
double sum_double = generic_add(3.5, 4.5); // 8.0
std::string s1 = "hello", s2 = " world";
std::string s_cat = generic_add(s1, s2); // "hello world" 
  • 捕获初始化 (C++14): 可以在捕获列表中直接创建和初始化新的变量,这个变量只在 Lambda 内部可见。这对于移动(move)一个只能移动的对象(如 std::unique_ptr)到 lambda 中特别有用。
std::unique_ptr<int> ptr = std::make_unique<int>(10);// 将 ptr 的所有权移动到 Lambda 内部的 p 变量中
auto lambda_move = [p = std::move(ptr)]() {std::cout << "Value inside lambda: " << *p << std::endl;
};
lambda_move();
//此时 ptr 已经是 nullptr 了
  • [*this] (C++17): 按值捕获 this 所指向的对象,即创建当前对象的一个副本。这在异步编程中非常有用,可以防止原始对象被销毁后,lambda 内部的 this 指针变成悬空指针。
http://www.dtcms.com/a/431505.html

相关文章:

  • 第 5 天:C 语言运算符与表达式 —— 数据处理的工具集
  • [深度学习] 大模型学习5-高效微调框架Unsloth使用指北
  • 家教网站代理做彩票网站是违法的吗
  • 南康网站建设wplms wordpress
  • 专注网站建设16年网站多级栏目
  • 四川建设厅电子证书官方网站我想做卖鱼苗网站怎样做
  • 所有字符的ASCII码值(0-127,按照序号、字符、描述、十进制、十六进制列表显示)(完整版)
  • 门控融合机制
  • 做本地的分类信息网站网络营销的特点是什么
  • grep 命令
  • 网站开发运营专业做足球体彩网站
  • 做外贸网站的价格最新新闻热点事件2021年10月
  • iBizModel 实体值规则模型(PSDEFVALUERULE)详解与应用
  • 大数据Spark(六十五):Transformation转换算子groupByKey和filter
  • sward入门到实战(11) - 如何有效保障文档的安全可靠
  • Qt---尺寸调整函数汇总
  • Linux 命令:nohup
  • 网站怎么制作做泉州互联网公司排名
  • 做ppt软件怎么下载网站电商网站系统建设考试
  • AI行业应用全景:从金融风控到智能制造的落地实践与技术解析
  • 公司网站怎么建立需要多少钱北京太阳宫网站建设
  • java线上问题排查-Java 进程CPU高
  • Vala编程语言高级特性-弱引用和所有权
  • Java反射和注解
  • 个人网站导航html源码哪家网站推广好
  • CentOS 7 网络连接问题
  • wordpress国内主题昆山网站优化建设
  • 宁波网站建设大概要多少钱宿州市做网站建设的公司
  • php快速建站工具网站建设策划书的心得
  • 机关公文写作网站公众号制作开发公司