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

第六章QT基础: Lambda表达式补充

什么是 Lambda 表达式?

Lambda 表达式(匿名函数)是一种可以在不定义函数名称的情况下直接定义并使用的小型函数。在 C++11 及更高版本中,Lambda 表达式使得编写临时函数变得更加简洁和直观。

Lambda 表达式通常用于:

  • 传递函数作为参数。
  • 在需要临时功能时避免定义额外的函数。

Lambda 表达式的基本语法

Lambda 表达式的基本语法格式如下:

[捕获列表] (参数列表) -> 返回类型 { 函数体 }

组成部分:

  1. 捕获列表 (Capture List):
    捕获列表用于指定外部变量如何在 Lambda 中使用。可以捕获外部作用域的变量,并决定是按值捕获还是按引用捕获。

    • [=]:按值捕获外部作用域中的所有变量。

    • [&]:按引用捕获外部作用域中的所有变量。

    • [var]:按值捕获指定的变量 var

    • [&var]:按引用捕获指定的变量 var

    • [=, &var]:按值捕获所有外部变量,并按引用捕获指定变量 var

  2. 参数列表 (Parameter List):
    Lambda 表达式接受的参数列表,和普通函数一样。

  3. 返回类型 (Return Type):
    -> 返回类型 用于显式声明 Lambda 表达式的返回类型。C++11 之后可以省略返回类型,编译器会自动推断。

  4. 函数体 (Body):
    函数体是 Lambda 表达式的执行逻辑,类似普通函数的实现部分。

Lambda 表达式的捕获列表详细说明

在 C++ 中,捕获列表 是用于指定如何将外部变量传递到 Lambda 表达式中的一部分。捕获列表可以选择按值(=)或按引用(&)来捕获变量,也可以只捕获特定的变量。接下来,我们将逐一讲解您提到的几种捕获方式。

1. [=]:按值捕获外部作用域中的所有变量

[=] 语法表示按值捕获所有外部变量。Lambda 表达式会创建外部变量的副本,并在 Lambda 内部使用这些副本。

  • 副本当 Lambda 表达式调用时它使用的是外部变量的副本,而不是外部原始变量的地址。因此,对 Lambda 内部捕获变量的修改不会影响外部的原始变量。
#include <iostream>int main() {int x = 10;int y = 20;// 按值捕获外部变量auto print_values = [=]() { std::cout << "x: " << x << ", y: " << y << std::endl;};x = 15;  // 修改外部 xy = 25;  // 修改外部 yprint_values();  // 输出:x: 10, y: 20(因为按值捕获,使用的是 x 和 y 的副本)return 0;
}
  • 输出
    x: 10, y: 20
    

解释

  • 即使在 print_values 调用时,xy 已经被修改,Lambda 仍然使用它们的原始值(10 和 20),因为它们在 Lambda 捕获时是按值捕获的。

2. [&]:按引用捕获外部作用域中的所有变量

[&] 语法表示按引用捕获所有外部变量。Lambda 表达式将直接使用外部变量的引用。因此,对 Lambda 内部捕获变量的修改会影响外部原始变量。

#include <iostream>int main() {int x = 10;int y = 20;// 按引用捕获外部变量auto modify_values = [&]() { x = 30;  // 修改外部 xy = 40;  // 修改外部 y};modify_values();  // 调用 Lambda,修改外部变量std::cout << "x: " << x << ", y: " << y << std::endl;  // 输出:x: 30, y: 40return 0;
}
  • 输出
    x: 30, y: 40
    

解释

  • Lambda 捕获外部变量 xy 时是按引用的,意味着修改 Lambda 内部的变量会直接影响外部变量 xy

3. [var]:按值捕获指定的变量 var

[var] 语法表示只按值捕获指定的变量 var。仅捕获指定的变量并创建该变量的副本,其他变量则不会被捕获。

#include <iostream>int main() {int x = 10;int y = 20;// 只按值捕获变量 xauto print_value = [x]() { std::cout << "x: " << x << std::endl;};x = 15;  // 修改外部 xprint_value();  // 输出:x: 10(因为按值捕获,Lambda 使用的是 x 的副本)return 0;
}
  • 输出

    x: 10
    

解释

  • 由于 x 是按值捕获的,所以即使在 Lambda 调用时修改了 x,Lambda 使用的仍然是 x 的副本。

4. [&var]:按引用捕获指定的变量 var

[&var] 语法表示只按引用捕获指定的变量 var,意味着 var 是通过引用捕获的,其他变量则不被捕获。

#include <iostream>int main() {int x = 10;int y = 20;// 只按引用捕获变量 yauto modify_y = [&y]() { y = 30;  // 修改 y};modify_y();  // 调用 Lambda,修改外部变量 ystd::cout << "y: " << y << std::endl;  // 输出:y: 30return 0;
}
  • 输出
    y: 30
    

解释

  • y 是按引用捕获的,因此 Lambda 内部对 y 的修改直接影响外部的 y。但 x 没有被捕获,因此它没有受到影响。

5. [=, &var]:按值捕获所有外部变量,并按引用捕获指定变量 var

[=, &var] 语法表示按值捕获所有外部变量,并按引用捕获特定变量 var。所有未显式列出的变量都会按值捕获,而 var 会按引用捕获。

#include <iostream>int main() {int x = 10;int y = 20;// 按值捕获所有外部变量,按引用捕获 yauto modify_values = [=, &y]() { std::cout << "x: " << x << ", y: " << y << std::endl;y = 50;  // 修改 y};modify_values();  // 修改 ystd::cout << "x: " << x << ", y: " << y << std::endl;  // 输出:x: 10, y: 50return 0;
}
  • 输出

    x: 10, y: 20
    x: 10, y: 50
    

解释

  • x 是按值捕获的,因此 Lambda 使用的是 x 的副本,外部 x 的值不会改变。

  • y 是按引用捕获的,因此在 Lambda 内部修改 y 时,外部的 y 也会被修改。

总结

  1. [=]:按值捕获所有外部变量,变量的副本会传递给 Lambda,修改不会影响外部变量。

  2. [&]:按引用捕获所有外部变量,Lambda 内部的修改会直接影响外部变量。

  3. [var]:按值捕获指定变量,只有指定变量会按值传递给 Lambda。

  4. [&var]:按引用捕获指定变量,只有指定变量会按引用传递给 Lambda。

  5. [=, &var]:按值捕获所有外部变量,并按引用捕获指定变量。

示例 1:基本的 Lambda 表达式

#include <iostream>int main() {// 定义一个 lambda 表达式,计算两个整数的和auto add = [](int a, int b) -> int {return a + b;};int result = add(5, 3);  // 调用 Lambda 表达式std::cout << "Result: " << result << std::endl;  // 输出:Result: 8return 0;
}

说明:

  • 捕获列表[],没有捕获外部变量。

  • 参数列表(int a, int b),表示 Lambda 表达式接收两个整数作为参数。

  • 返回类型-> int,表示 Lambda 表达式返回一个整数。

  • 函数体return a + b;,实现了加法操作。

示例 2:按值捕获外部变量

#include <iostream>int main() {int x = 10;int y = 20;// 按值捕获外部变量auto add = [=]() -> int { return x + y; };// 修改 x 和 y 的值x = 15;y = 25;std::cout << "Result: " << add() << std::endl;  // 输出:Result: 30return 0;
}

说明:

  • 捕获列表[=],表示按值捕获所有外部变量。

  • 返回值:即使 xy 在 Lambda 表达式调用时被修改,Lambda 仍然使用它们被捕获时的值。

示例 3:按引用捕获外部变量

#include <iostream>int main() {int x = 10;int y = 20;// 按引用捕获外部变量auto add = [&]() -> int { x += 5;  // 修改外部变量 xreturn x + y; };std::cout << "Result: " << add() << std::endl;  // 输出:Result: 35std::cout << "x: " << x << ", y: " << y << std::endl;  // 输出:x: 15, y: 20return 0;
}

说明:

  • 捕获列表[&],按引用捕获外部变量 xy,这意味着在 Lambda 表达式内对这些变量的修改会影响外部的变量。

示例 4:捕获特定变量

#include <iostream>int main() {int x = 10;int y = 20;// 捕获特定变量(按值捕获 x 和按引用捕获 y)auto add = [x, &y]() -> int { y = y + 5;  // 修改 yreturn x + y;  // 使用捕获的 x 和修改后的 y};std::cout << "Result: " << add() << std::endl;  // 输出:Result: 35std::cout << "x: " << x << ", y: " << y << std::endl;  // 输出:x: 10, y: 25return 0;
}

说明:

  • 捕获列表[x, &y],表示按值捕获 x,按引用捕获 yx 的值不会变化,而 y 会发生变化。

  • 调用结果:Lambda 使用捕获时的 x(10),同时修改 y 的值。

示例 5:无参数的 Lambda 表达式

#include <iostream>int main() {// 一个不带参数的简单 lambda 表达式auto greet = []() { std::cout << "Hello, World!" << std::endl; };greet();  // 输出:Hello, World!return 0;
}

说明:

  • 捕获列表[],没有捕获外部变量。

  • 参数列表(),不接受任何参数。

  • 函数体:输出 Hello, World!

示例 6:使用 Lambda 表达式作为参数

Lambda 表达式常用于作为函数的参数,特别是在 STL 算法中。

#include <iostream>
#include <vector>
#include <algorithm>int main() {std::vector<int> numbers = {1, 2, 3, 4, 5};// 使用 lambda 表达式作为 std::for_each 的参数std::for_each(numbers.begin(), numbers.end(), [](int num) {std::cout << num << " ";});std::cout << std::endl;return 0;
}

说明:

  • Lambda 表达式[](int num) { std::cout << num << " "; },在 std::for_each 中使用 Lambda 遍历容器 numbers,并输出每个元素。

示例 7:Lambda 表达式的返回类型推导

C++14 引入了 Lambda 表达式返回类型推导,编译器会自动推导 Lambda 的返回类型,减少冗余的类型声明。

#include <iostream>int main() {auto add = [](int a, int b) { return a + b;  // 自动推导返回类型};std::cout << "Result: " << add(5, 3) << std::endl;  // 输出:Result: 8return 0;
}

说明:

  • 返回类型推导:没有显式声明返回类型,编译器自动推导返回值的类型(此例为 int)。

总结

Lambda 表达式在 C++ 中提供了一种简洁的方式来创建匿名函数,它有以下特点:

  • 简洁:无须为小功能编写额外的函数。

  • 灵活:能够捕获外部变量,通过值或引用捕获外部作用域中的变量。

  • 强大:广泛应用于 STL 算法中,作为函数参数传递。

使用场景:

  • 临时函数:不需要重复使用的函数可以使用 Lambda 表达式。

  • 回调函数:作为回调函数传递给 STL 算法或事件处理器。

  • 事件处理:在 GUI 编程中,Lambda 表达式常用于信号和槽的连接。

Lambda 表达式极大地提高了代码的简洁性和可读性,是现代 C++ 编程的重要工具之一。

http://www.xdnf.cn/news/435079.html

相关文章:

  • [250513] “End of 10” 活动:应对 Windows 10 支持终止,推广 Linux 转型
  • livenessProbe 和 readinessProbe 最佳实践
  • Pytorch学习笔记(二十二)Audio - Audio I/O
  • 论文《Collaboration-Aware Graph Convolutional Network for Recommender Systems》阅读
  • 打卡DAY24
  • 【调度算法】LaCAM快速多智能体路径搜索算法
  • LLM大模型transform架构的核心知识
  • 《从协议层面剖析 VoIP 通信:SIP 信令流中的 RPort、注册与呼叫建立机制》
  • 20250512期:基于arcpy数据驱动的大批量规范化出图
  • 油桃缺陷检测数据集VOC+YOLO格式559张2类别
  • AI助力:零基础开启编程之旅
  • 【JavaScript】原生 JavaScript 实现 localStorage 过期时间
  • Linux常用命令39——free显示系统内存使用量情况
  • 软件测试——面试八股文(入门篇)
  • 项目三 - 任务6:回文日期判断
  • 飞拍技术介绍
  • 从数据中台到数据飞轮:数字化转型的演进之路
  • Google Earth Engine(GEE) 代码详解:批量计算_年 NDVI 并导出(附 Landsat 8 数据处理全流程)
  • 这类物种组织heatmap有点东西
  • MySQL初阶:查询进阶
  • 京东平台商品评论接口接入指南与代码实现
  • D-Hank‘s平衡盐溶液(D-HBSS)无酚红设计 守护细胞活性与数据精准
  • 重生之我是CSDN大佬
  • Spark,RDD中的行动算子
  • curl发送数据不为null,但是后端接收到为null
  • 电子行业专利管理突破:全方位助力创新保护
  • SQL易混点:你知道ON 和 WHERE 的区别吗
  • 在服务器排查java某个线程导致CPU飙高教程
  • 前端实用工具|JavaScript 身份证号合法性校验工具类全解析
  • openFeign远程调用