前言: Lambda 表达式是一种强大而灵活的工具,它允许我们直接在代码中定义匿名函数对象。

一、初识 Lambda 表达式

Lambda 表达式是一种匿名函数,它没有名字,但具有函数的特性。它的基本语法结构如下:

capture list->return type {body}
  • 捕获列表(Capture list):规定 Lambda 表达式可以访问哪些外部变量。

  • 参数列表(Parameters):与普通函数的参数列表相同。

  • 返回类型(Return type):可选部分,默认由编译器推断。

  • 函数体(Body):包含函数的具体实现代码。

最简单的 Lambda 表达式示例:

#include <iostream>

int main() {
    auto lambda = []() { std::cout << "Lambda 表达式:你好,世界!" << std::endl; };
    lambda(); // 调用 Lambda 表达式
    return 0;
}

在这个例子中,我们定义了一个没有参数、没有返回值的 Lambda 表达式,auto 关键字用于自动推断其类型。运行程序会输出:“Lambda 表达式:你好,世界!”

二、捕获机制详解

Lambda 表达式可以通过捕获列表访问其定义所在作用域中的变量。

1. 按值捕获(Copy Capture):[=]

#include <iostream>

int main() {
    int x = 10;
    int y = 20;
    auto lambda = [=]() { std::cout << "按值捕获:x = " << x << ", y = " << y << std::endl; };
    lambda();
    return 0;
}

在这个例子中,Lambda 表达式捕获了 xy 的值。这意味着即使在 Lambda 表达式定义之后修改 xy,Lambda 表达式内部的值也不会改变。程序输出:“按值捕获:x = 10, y = 20”

2. 按引用捕获(Reference Capture):[&]

#include <iostream>

int main() {
    int x = 10;
    int y = 20;
    auto lambda = [&](int a) { x = a; std::cout << "按引用捕获:x = " << x << ", y = " << y << std::endl; };
    lambda(30);
    std::cout << "主函数中 x 的值: " << x << std::endl; // 输出修改后的 x 值
    return 0;
}

在这个例子中,Lambda 表达式捕获了 xy 的引用。修改 Lambda 表达式中的 x 值会直接影响到原始变量 x。程序输出:

按引用捕获:x = 30, y = 20
主函数中 x 的值: 30

3. 显式捕获

可以显式指定捕获哪些变量以及捕获方式:

#include <iostream>

int main() {
    int x = 10;
    int y = 20;
    auto lambda = [x, &y]() { std::cout << "显式捕获:x = " << x << ", y = " << y << std::endl; };
    lambda();
    return 0;
}

这里,x 按值捕获,y 按引用捕获。程序输出:“显式捕获:x = 10, y = 20”

三、Lambda 表达式的应用场景

1. 算法库中的使用

C++ 标准库中的算法库(如 sortfor_each 等)常需要函数对象作为参数,Lambda 表达式可以方便地定义这些函数对象。

  • 自定义排序规则

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

int main() {
    std::vector<int> vec = {5, 2, 8, 1, 3};
    std::sort(vec.begin(), vec.end(), [](int a, int b) { return a > b; }); // 按降序排序
    for (int x : vec) {
        std::cout << x << " ";
    }
    std::cout << std::endl;
    return 0;
}

程序输出:

8 5 3 2 1

2. 多线程编程中的使用

在多线程编程中,Lambda 表达式可以用于定义线程的任务函数,捕获当前作用域中的变量并在线程中使用。

#include <iostream>
#include <thread>

int main() {
    int x = 5;
    std::thread t([x] {
        std::cout << "线程中捕获的值:x = " << x << std::endl;
    });
    t.join();
    return 0;
}

程序输出:

线程中捕获的值:x = 5

3. 回调函数的使用

在需要传递回调函数的场景下,Lambda 表达式可以提供简洁的解决方案。

#include <iostream>
#include <vector>
#include <functional>

class EventHandler {
public:
    void addCallback(std::function<void()> callback) {
        callbacks.push_back(callback);
    }

    void trigger() {
        for (auto& callback : callbacks) {
            callback();
        }
    }

private:
    std::vector<std::function<void()>> callbacks;
};

int main() {
    EventHandler handler;
    int x = 10;
    handler.addCallback([x] {
        std::cout << "事件触发,捕获的值:x = " << x << std::endl;
    });
    handler.trigger();
    return 0;
}

程序输出:

事件触发,捕获的值:x = 10

四、Lambda 表达式的进阶用法

1. 带参数和返回值的 Lambda 表达式

Lambda 表达式可以有参数和返回值,就像普通函数一样。

#include <iostream>

int main() {
    auto add = [](int a, int b) { return a + b; };
    std::cout << "两数之和: " << add(3, 5) << std::endl; // 输出 8
    return 0;
}

2. Lambda 表达式的递归调用

Lambda 表达式可以进行递归调用,但需要捕获自身。

#include <iostream>

int main() {
    auto factorial = [&factorial](int n) {
        if (n <= 1) return 1;
        return n * factorial(n - 1);
    };
    std::cout << "5 的阶乘: " << factorial(5) << std::endl; // 输出 120
    return 0;
}

3. Lambda 表达式与成员函数

Lambda 表达式可以调用类的成员函数。

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

class MyClass {
public:
    int getValue() const { return value; }
    void setValue(int v) { value = v; }
private:
    int value;
};

int main() {
    MyClass obj;
    obj.setValue(10);

    auto printValue = [&obj]() {
        std::cout << "类成员函数调用:value = " << obj.getValue() << std::endl;
    };

    printValue(); // 输出 10
    return 0;
}

总结

C++ Lambda 表达式是一种强大而灵活的工具,它允许我们在代码中直接定义匿名函数对象。通过捕获机制,Lambda 表达式可以访问外部变量,这使得它在算法库、多线程编程、回调函数等场景中非常有用。Lambda 表达式不仅可以简化代码结构,还能提高代码的可读性和可维护性。 

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐