C++的lambda表达式

在 C++ 中,lambda 表达式(或匿名函数)是一种简洁的方式来定义函数对象或小型的临时函数。它引入于 C++11,并在 C++14C++17 中得到了进一步扩展。Lambda 表达式的主要特点是能够在函数中内联定义临时逻辑,而无需显式声明一个函数。

基本语法

C++ 的 lambda 表达式的一般形式是:

1
[capture](parameters) -> return_type { body }
  • [capture]:捕获列表,用于指定 lambda 如何访问其外部作用域中的变量。
  • (parameters):参数列表,类似普通函数的参数列表。
  • -> return_type(可选):返回值类型。如果可以自动推断返回类型,则可以省略。
  • { body }:函数体,包含要执行的逻辑。

简单示例

以下是一个简单的 lambda 表达式示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>
#include <vector>
#include <algorithm>

int main() {
std::vector<int> nums = {1, 2, 3, 4, 5};

// 使用 lambda 表达式打印每个数字
std::for_each(nums.begin(), nums.end(), [](int num) {
std::cout << num << " ";
});

return 0;
}

输出

1
1 2 3 4 5

捕获列表([capture]

捕获列表定义了 lambda 如何访问外部变量。常见的捕获方式包括:

  1. 按值捕获[x]):
    将外部变量的值拷贝到 lambda 中。lambda 内的修改不会影响外部变量。

    1
    2
    3
    4
    5
    int x = 10;
    auto f = [x]() { std::cout << x << std::endl; };
    f(); // 输出 10
    x = 20; // 修改外部的 x
    f(); // 仍然输出 10(lambda 内的 x 是拷贝)
  2. 按引用捕获[&x]):
    lambda 捕获的是变量的引用,lambda 内对变量的修改会影响外部变量。

    1
    2
    3
    4
    int x = 10;
    auto f = [&x]() { x += 5; };
    f(); // 修改了外部的 x
    std::cout << x << std::endl; // 输出 15
  3. 捕获全部变量

    • [=]:按值捕获所有外部变量。
    • [&]:按引用捕获所有外部变量。
    1
    2
    3
    int a = 5, b = 10;
    auto lambda1 = [=]() { return a + b; }; // 按值捕获
    auto lambda2 = [&]() { b += a; }; // 按引用捕获
  4. 混合捕获
    捕获特定变量,同时按值或引用捕获其他变量。

    1
    2
    int a = 5, b = 10;
    auto lambda = [a, &b]() { b += a; }; // a 按值捕获,b 按引用捕获

返回值

C++11 中,lambda 的返回值通常是自动推断的:

1
2
3
4
5
6
auto lambda = [](int x, int y) {
if (x > y)
return x;
else
return y;
}; // 返回值自动推断为 int

如果返回值类型不一致,编译器则会报错。

如果返回类型复杂或需要显式指定,可以使用 -> return_type

1
2
3
auto lambda = [](int x, int y) -> double {
return x / static_cast<double>(y);
};

Lambda 表达式的实际用途

  1. 排序
    使用 lambda 定义自定义的排序逻辑:

    1
    2
    3
    4
    std::vector<int> nums = {5, 2, 8, 1};
    std::sort(nums.begin(), nums.end(), [](int a, int b) {
    return a > b; // 按降序排序
    });
  2. 过滤
    使用 lambda 筛选元素:

    1
    2
    3
    4
    std::vector<int> nums = {1, 2, 3, 4, 5};
    nums.erase(std::remove_if(nums.begin(), nums.end(), [](int x) {
    return x % 2 == 0; // 移除所有偶数
    }), nums.end());
  3. 异步操作
    使用 lambda 编写回调函数:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    #include <thread>
    #include <iostream>

    int main() {
    std::thread t([]() {
    std::cout << "Hello from lambda in a thread!" << std::endl;
    });
    t.join();
    return 0;
    }

注意事项

  1. 捕获列表的生命周期
    捕获的变量按值或按引用会影响它的生命周期:

    • 按值捕获是拷贝,原变量的修改不会影响捕获的值。
    • 按引用捕获需要确保变量在 lambda 的生命周期内仍然有效。
  2. 可变 lambda
    默认情况下,当lambda使用按值捕获([x])时,是不可修改捕获的值的:

    1
    2
    3
    int x = 10;
    auto lambda = [x]() { x += 5; std::cout << x << std::endl; }; // 这里会报错:表达式必须是可修改的左值

    如果需要修改捕获的值,可以用 mutable 关键字,mutable 允许修改捕获的副本(注意,是副本,不是原来的x

    1
    2
    3
    4
    int x = 10;
    auto lambda = [x]() mutable { x += 5; std::cout << x << std::endl; };
    lambda(); // 输出 15
    std::cout << x << std::endl; // 原来的 x 仍然是 10
  3. 嵌套 lambda
    Lambda 表达式可以嵌套使用:

    1
    2
    3
    4
    5
    6
    auto outer = [](int x) {
    return [x](int y) { return x + y; };
    };

    auto inner = outer(10);
    std::cout << inner(5) << std::endl; // 输出 15

总结

Lambda 表达式使得 C++ 更加灵活,尤其是在需要传递临时函数或函数对象的场景中(例如排序、回调等)。使用它可以大大减少代码的冗余,提高代码的可读性和可维护性。


C++的lambda表达式
https://blog.supersource.top/lambda_in_cpp/
作者
看热闹的咸鱼
发布于
2025年1月11日
许可协议