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

C++ 函数式编程Lambda表达式

C++ 是一门支持多种编程范式的语言,包括 函数式编程。在函数式编程中,函数被视为一等公民,可以像数据一样传递、返回,甚至被赋值给变量。C++ 引入的 Lambda 表达式 是支持函数式编程的一个重要特性。接下来,我们将详细介绍 函数式编程 在 C++ 中的应用,以及 Lambda 表达式 的语法、变量捕获规则和泛型用法。

一、C++中的函数式编程

函数式编程(Functional Programming) 是一种编程范式,其中函数是 一等公民(first-class citizens)。这意味着函数可以像其他数据类型一样被传递、赋值、返回等。

C++ 作为一门多范式语言,既支持面向对象编程(OOP),也支持函数式编程。C++11 引入了 Lambda 表达式,使得函数式编程在 C++ 中变得更加自然。

1. 函数作为一等公民

在 C++ 中,函数可以像数据一样被操作。您可以通过以下方式将函数作为一等公民使用:

  • 将函数指针作为参数传递给其他函数
  • 将函数作为返回值返回
  • 将函数指针赋值给变量

例如:

#include <iostream>
using namespace std;

// 普通函数
int add(int x, int y) {
    return x + y;
}

// 将函数作为参数传递
void operate(int x, int y, int (*func)(int, int)) {
    cout << "Result: " << func(x, y) << endl;
}

int main() {
    // 将 add 函数作为参数传递
    operate(5, 3, add);  // 输出 Result: 8
    return 0;
}

二、Lambda 表达式

Lambda 表达式 是 C++11 引入的一个强大的特性,它让我们能够方便地定义匿名函数并在需要时使用它们。Lambda 表达式特别适合在算法、回调和并发等场景中使用。

1. Lambda 表达式的语法形式

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

[捕获列表](参数列表) -> 返回类型 { 函数体 }
  • 捕获列表([]:指定如何捕获外部变量。可以按值捕获、按引用捕获等。
  • 参数列表((int x):和普通函数一样,Lambda 表达式可以接受参数。
  • 返回类型(-> 返回类型:指定 Lambda 的返回类型。如果返回类型可以自动推导,可以省略。
  • 函数体({}:Lambda 表达式的实际实现。
示例:
#include <iostream>
using namespace std;

int main() {
    // Lambda 表达式,计算两个数的和
    auto add = [](int a, int b) -> int {
        return a + b;
    };

    cout << add(3, 4) << endl;  // 输出 7
    return 0;
}

在这个示例中,我们定义了一个 Lambda 表达式 add,它接受两个整数参数并返回它们的和。

2. 变量捕获规则

Lambda 表达式可以访问外部作用域中的变量。通过 捕获列表([] 来指定如何捕获外部变量。C++ 支持按 值捕获按引用捕获 两种方式。

  • 按值捕获([=]:捕获外部变量的副本。
  • 按引用捕获([&]:捕获外部变量的引用。
  • 显式捕获:指定单个或多个变量的捕获方式
示例:
#include <iostream>
using namespace std;

int main() {
    int n = 10;
	int x = 5, y = 10;
    // 按值捕获外部变量 n
    auto byValue = [=](int x) {
        cout << "By Value: " << x * n << endl;  // 使用捕获的副本 n
    };

    // 按引用捕获外部变量 n
    auto byReference = [&](int x) {
        cout << "By Reference: " << x * n << endl;  // 使用 n 的引用
        n = 20;  // 修改 n
    };

	auto printXY = [=, &y]() {
	    cout << "x = " << x << ", y = " << y << endl;  // x 按值捕获,y 按引用捕获
	    y = 20;  // 修改 y
	};
    byValue(3);  // 输出 By Value: 30
    cout << "n after byValue: " << n << endl;  // 输出 n after byValue: 10 (n 不变)

    byReference(3);  // 输出 By Reference: 30
    cout << "n after byReference: " << n << endl;  // 输出 n after byReference: 20 (n 被修改)

    return 0;
}
  • byValue 按值捕获外部变量 n,Lambda 内部使用的是 n 的副本,修改外部 n 不会影响 Lambda 内部的副本。
  • byReference 按引用捕获外部变量 n,Lambda 内部直接操作外部 n,修改 n 会影响外部 n
3. 泛型 Lambda

C++14 引入了 泛型 Lambda(Generic Lambda),允许我们在 Lambda 表达式中使用 auto 关键字来声明参数类型,从而使得 Lambda 可以适用于多种类型。

示例:
#include <iostream>
using namespace std;

int main() {
    // 泛型 Lambda
    auto print = [](auto x) {
        cout << x << endl;
    };

    print(42);          // 输出 42
    print(3.14);        // 输出 3.14
    print("Hello");     // 输出 Hello

    return 0;
}

在这个示例中,Lambda 使用 auto 来表示它可以接受任何类型的参数,且能够根据传入参数的类型自动推导。

泛型 Lambda 与模板函数的对比:
  • 模板函数:在编译时确定函数的类型。
  • 泛型 Lambda:提供了更简洁的语法,能够在运行时根据输入的类型自动推导。

三、Lambda 表达式的完整示例

让我们结合之前的内容,创建一个更为完整的 Lambda 表达式示例,涵盖捕获规则、参数、返回类型和泛型 Lambda:

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int main() {
    // 定义一个包含整数的向量
    vector<int> nums = {1, 2, 3, 4, 5};

    // 按值捕获并传递参数,计算平方
    int multiplier = 2;
    auto squareAndMultiply = [=](int x) -> int {
        return x * x * multiplier;
    };

    // 使用标准库算法 for_each 传递 Lambda 表达式
    for_each(nums.begin(), nums.end(), [&](int n) {
        cout << squareAndMultiply(n) << " ";  // 输出平方并乘以 multiplier
    });
    cout << endl;

    // 泛型 Lambda 用于不同类型的数据
    auto print = [](auto x) {
        cout << x << endl;
    };

    print(42);        // 输出 42
    print(3.14);      // 输出 3.14
    print("Hello");   // 输出 Hello

    return 0;
}

总结

  1. Lambda 表达式:C++11 引入的匿名函数,支持捕获外部变量并简洁地表达函数逻辑。

    • 基本语法:捕获列表 -> 返回类型 { 函数体 }
  2. 变量捕获规则

    • [=] 按值捕获外部变量的副本。
    • [&] 按引用捕获外部变量的引用。
  3. 泛型 Lambda:C++14 引入,允许 Lambda 使用 auto 来接受任何类型的参数,实现类似模板函数的效果。


http://www.kler.cn/a/459472.html

相关文章:

  • 组网实训实现
  • Git快速入门(三)·远程仓库GitHub以及Gitee的使用
  • Redis(二)value 的五种常见数据类型简述
  • CSS系列(45)-- Scope详解
  • log4j2的Strategy、log4j2的DefaultRolloverStrategy、删除过期文件
  • Mac 版本向日葵退出登录账号
  • 磁编码器(Magnetic Encoder)
  • 【每日学点鸿蒙知识】Web嵌套滚动体验、拷贝传递 ArrayBuffer异常问题、ObjectLink 的属性传递、构建读取参数
  • 【高阶数据结构】红黑树封装map、set
  • leetcode hot100 tire前缀树
  • go语言中zero框架项目日志收集与配置
  • 【2024年-7月-6日-开源社区openEuler实践记录】探秘 Qingzhou:开启高效开发与运维新旅程
  • 012-spring的注解开发、bean的属性、IOC实现原理
  • 【服务器】上传文件到服务器并训练深度学习模型下载服务器文件到本地
  • 基于GA遗传优化TCN-LSTM时间卷积神经网络时间序列预测算法matlab仿真
  • EL表达式与JSTL
  • Quo Vadis, Anomaly Detection? LLMs and VLMs in the Spotlight 论文阅读
  • Java基础(三):桌球案例
  • Qt https请求报错SSL handshake failed 解决思路方法
  • AI大模型-提示工程学习笔记0
  • 进程通信(8)读写锁
  • LabVIEW手部运动机能实验系统
  • 使用工厂+策略模式实现去除繁琐的if else
  • 菲尼克斯超级工厂落地南京,汽车市场被瞄准
  • FreeRTOS的时间管理
  • CSS过渡(transition)