C++ 中的 Lambda 表达式(回调函数语法)

发布于:2025-06-26 ⋅ 阅读:(16) ⋅ 点赞:(0)

Lambda 表达式是 C++11 引入的一项重要特性,它允许我们定义匿名函数对象(闭包),非常适合用作回调函数。下面我将详细介绍 C++ 中 lambda 表达式的语法和使用方法。

基本语法

Lambda 表达式的基本形式如下:

[capture](parameters) -> return_type { 
    // 函数体
}

组成部分

  1. 捕获列表 (capture):定义 lambda 表达式可以访问的外部变量

  2. 参数列表 (parameters):与普通函数的参数列表类似

  3. 返回类型 (return_type):可选的,通常可以自动推导

  4. 函数体:包含 lambda 表达式的代码

捕获列表详解

捕获列表决定了 lambda 表达式如何访问外部变量:

  • []:不捕获任何变量

  • [=]:以值的方式捕获所有外部变量

  • [&]:以引用的方式捕获所有外部变量

  • [x]:只以值的方式捕获 x。按值传递变量,Lambda会复制变量的值。原始变量的修改不会影响Lambda内部的副本。

  • [&x]:只以引用的方式捕获 x。按引用传递变量,Lambda直接访问原始变量。原始变量的修改会影响Lambda内部的访问。

  • [=, &x]:以值的方式捕获所有变量,但以引用的方式捕获 x

  • [&, x]:以引用的方式捕获所有变量,但以值的方式捕获 x

示例代码

基本示例

#include <iostream>

int main() {
    // 最简单的 lambda 表达式。auto greet:将 lambda 赋值给一个变量,这样我们可以多次调用它
    auto greet = []() {
        std::cout << "Hello, World!" << std::endl;
    };
    greet();  // 调用 lambda
    

    // 带参数的 lambda
    auto add = [](int a, int b) {
        return a + b;
    };
    std::cout << "5 + 3 = " << add(5, 3) << std::endl;
    

    // 带捕获的 lambda
    int x = 10;
    auto increment = [x](int y) {  // [x]:以值的方式捕获外部变量 x(创建 x 的副本)
        return x + y;
    };
    std::cout << "10 + 5 = " << increment(5) << std::endl;
    
    return 0;
}

作为回调函数使用

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> numbers = {1, 2, 3, 4, 5}; //std::vector:动态数组,支持快速随机访问。
    
    // 使用 lambda 作为回调函数
    std::for_each(numbers.begin(), numbers.end(), [](int n) { //std::for_each:STL 算法,对范围内的每个元素执行操作
        std::cout << n * 2 << " ";
    });
    std::cout << std::endl;  //输出:2 4 6 8 10
    

    // 带捕获的 lambda 回调
    int threshold = 3;
    //std::count_if:计算满足条件的元素数量
    auto count = std::count_if(numbers.begin(), numbers.end(), 
        [threshold](int n) { return n > threshold; });
    std::cout << count << " numbers > " << threshold << std::endl;  //输出大于 3 的数字数量(2 个:4 和 5)
    
    return 0;
}

可变 lambda(修改值捕获的变量)

#include <iostream>

int main() {
    int x = 0;
    
    // 默认情况下,值捕获的变量是只读的
    // 使用 mutable 关键字允许修改值捕获的变量
    auto increment = [x]() mutable {
        x++;  // 修改的是副本
        std::cout << "Inside lambda: " << x << std::endl;
    };
    
    increment();
    increment();
    std::cout << "Outside lambda: " << x << std::endl;
    
    return 0;
}
  • 每次调用 increment(),lambda 内部的 x 副本会增加,外部的 x 保持不变

  • 输出:

    Inside lambda: 1
    Inside lambda: 2
    Outside lambda: 0

返回类型指定

当 lambda 体包含多条返回语句或返回类型不明显时,可以显式指定返回类型:

#include <iostream>

int main() {
    // 显式指定返回类型,显式指定返回类型为 double
    auto divide = [](double a, double b) -> double {
        if (b == 0.0) {
            return 0.0;  // 需要显式返回类型,因为可能有不同的返回路径
        }
        return a / b;
    };
    
    std::cout << "10 / 3 = " << divide(10, 3) << std::endl;
    std::cout << "10 / 0 = " << divide(10, 0) << std::endl;
    
    return 0;
}

在 STL 算法中的应用

Lambda 表达式与 STL 算法结合使用时非常强大:

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> numbers = {5, 2, 8, 3, 1, 9, 4};
    
    // 排序 - 降序
    std::sort(numbers.begin(), numbers.end(), [](int a, int b) {
        return a > b;
    });
    
    // 查找第一个大于5的数
    auto it = std::find_if(numbers.begin(), numbers.end(), [](int n) {
        return n > 5;
    });
    
    if (it != numbers.end()) {
        std::cout << "First number > 5: " << *it << std::endl;
    }
    
    // 计算所有偶数的和
    int sum = 0;
    std::for_each(numbers.begin(), numbers.end(), [&sum](int n) {
        if (n % 2 == 0) sum += n;
    });
    std::cout << "Sum of even numbers: " << sum << std::endl;
    
    return 0;
}

通用 lambda (C++14)

C++14 引入了通用 lambda,可以使用 auto 作为参数类型,。auto x:参数类型自动推导,可以接受任何类型的参数,编译器会为每种使用到的类型生成对应的函数。

#include <iostream>

int main() {
    // 通用 lambda - 参数类型自动推导
    auto print = [](auto x) {
        std::cout << x << std::endl;
    };
    
    print(42);          // int
    print(3.14);        // double
    print("Hello");     // const char*
    
    return 0;
}

初始化捕获 (C++14)

C++14 允许在捕获列表中初始化变量:

#include <iostream>
#include <memory>

int main() {
    auto ptr = std::make_unique<int>(42);
    
    // 初始化捕获 - 移动 unique_ptr
    auto lambda = [value = std::move(ptr)]() {
        std::cout << *value << std::endl;
    };
    
    lambda();
    
    return 0;
}
  • value = std::move(ptr):在捕获列表中初始化 value

  • 使用 std::move 将 unique_ptr 的所有权转移给 lambda

  • lambda 现在拥有这个指针,外部 ptr 变为 nullptr


网站公告

今日签到

点亮在社区的每一天
去签到