跳转到内容

C++ lambda 表达式

来自代码酷
Admin留言 | 贡献2025年4月28日 (一) 21:26的版本 (Page creation by admin bot)

(差异) ←上一版本 | 已核准修订 (差异) | 最后版本 (差异) | 下一版本→ (差异)

C++ Lambda表达式[编辑 | 编辑源代码]

Lambda表达式是C++11引入的一项强大特性,它允许在代码中定义匿名函数对象(也称为闭包)。Lambda表达式常用于简化代码、实现回调函数或在需要临时函数的场景中使用。

基本语法[编辑 | 编辑源代码]

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

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

其中:

  • 捕获列表:指定lambda表达式可以访问的外部变量
  • 参数列表:与普通函数的参数列表类似
  • 返回类型:可选的,如果省略则由编译器自动推导
  • 函数体:包含要执行的代码

最简单的Lambda示例[编辑 | 编辑源代码]

#include <iostream>

int main() {
    auto greet = []() { std::cout << "Hello, World!"; };
    greet();  // 调用lambda
    return 0;
}

输出:

Hello, World!

捕获列表详解[编辑 | 编辑源代码]

Lambda表达式可以通过捕获列表访问外部变量,有以下几种捕获方式:

捕获方式比较
捕获方式 语法 描述
值捕获 [x] 创建x的副本
引用捕获 [&x] 引用外部变量x
隐式值捕获 [=] 以值方式捕获所有外部变量
隐式引用捕获 [&] 以引用方式捕获所有外部变量
混合捕获 [=, &x] 大部分变量值捕获,x引用捕获

捕获示例[编辑 | 编辑源代码]

#include <iostream>

int main() {
    int x = 10, y = 20;
    
    // 值捕获x,引用捕获y
    auto lambda = [x, &y]() {
        std::cout << "x: " << x << ", y: " << y << "\n";
        y++;  // 可以修改y,因为它是引用捕获
    };
    
    lambda();
    std::cout << "After lambda, y is now: " << y << "\n";
    
    return 0;
}

输出:

x: 10, y: 20
After lambda, y is now: 21

参数和返回类型[编辑 | 编辑源代码]

Lambda表达式可以像普通函数一样接受参数和指定返回类型。

带参数的Lambda[编辑 | 编辑源代码]

#include <iostream>

int main() {
    auto add = [](int a, int b) { return a + b; };
    std::cout << "5 + 3 = " << add(5, 3) << "\n";
    return 0;
}

输出:

5 + 3 = 8

指定返回类型[编辑 | 编辑源代码]

当函数体包含多个返回语句且类型不同,或者返回类型不明显时,需要显式指定返回类型。

#include <iostream>

int main() {
    auto divide = [](double a, double b) -> double {
        if(b == 0) return 0;  // 返回double而非int
        return a / b;
    };
    
    std::cout << "10 / 3 = " << divide(10, 3) << "\n";
    std::cout << "10 / 0 = " << divide(10, 0) << "\n";
    
    return 0;
}

输出:

10 / 3 = 3.33333
10 / 0 = 0

通用Lambda (C++14)[编辑 | 编辑源代码]

C++14引入了通用Lambda,可以使用auto作为参数类型。

#include <iostream>

int main() {
    auto print = [](auto value) {
        std::cout << value << "\n";
    };
    
    print(42);        // int
    print(3.14);      // double
    print("Hello");   // const char*
    
    return 0;
}

输出:

42
3.14
Hello

初始化捕获 (C++14)[编辑 | 编辑源代码]

C++14允许在捕获列表中初始化变量,这在使用移动语义时特别有用。

#include <iostream>
#include <string>
#include <utility>

int main() {
    std::string str = "Hello";
    
    // 移动捕获str
    auto lambda = [s = std::move(str)]() {
        std::cout << s << "\n";
    };
    
    lambda();
    std::cout << "str is now: " << str << "\n";  // str已被移动
    
    return 0;
}

输出:

Hello
str is now: 

可变Lambda[编辑 | 编辑源代码]

默认情况下,值捕获的变量在lambda内是const的。使用mutable关键字可以修改这些副本。

#include <iostream>

int main() {
    int x = 0;
    
    auto counter = [x]() mutable {
        x++;  // 修改副本
        return x;
    };
    
    std::cout << counter() << "\n";  // 1
    std::cout << counter() << "\n";  // 2
    std::cout << "Original x: " << x << "\n";  // 仍然是0
    
    return 0;
}

输出:

1
2
Original x: 0

实际应用案例[编辑 | 编辑源代码]

STL算法中的Lambda[编辑 | 编辑源代码]

Lambda表达式常用于STL算法中作为谓词。

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

int main() {
    std::vector<int> numbers = {5, 2, 8, 1, 9, 3};
    
    // 使用lambda排序
    std::sort(numbers.begin(), numbers.end(), [](int a, int b) {
        return a > b;  // 降序排序
    });
    
    for(int n : numbers) {
        std::cout << n << " ";
    }
    
    return 0;
}

输出:

9 8 5 3 2 1 

异步编程中的回调[编辑 | 编辑源代码]

Lambda非常适合作为异步操作的回调函数。

#include <iostream>
#include <thread>
#include <chrono>

int main() {
    std::cout << "Starting async operation...\n";
    
    std::thread worker([]() {
        std::this_thread::sleep_for(std::chrono::seconds(2));
        std::cout << "Async operation completed!\n";
    });
    
    std::cout << "Main thread continues...\n";
    worker.join();
    
    return 0;
}

输出:

Starting async operation...
Main thread continues...
Async operation completed!

Lambda与函数指针[编辑 | 编辑源代码]

Lambda表达式可以转换为函数指针,前提是它不捕获任何变量。

#include <iostream>

void call_func(void (*func)(const char*)) {
    func("Hello from function pointer");
}

int main() {
    // 无捕获的lambda可以转换为函数指针
    auto lambda = [](const char* msg) {
        std::cout << msg << "\n";
    };
    
    call_func(lambda);
    
    return 0;
}

输出:

Hello from function pointer

Lambda表达式的类型[编辑 | 编辑源代码]

每个Lambda表达式都有唯一的、未命名的类型。可以使用autostd::function来存储Lambda。

使用std::function[编辑 | 编辑源代码]

#include <iostream>
#include <functional>

int main() {
    std::function<int(int, int)> add = [](int a, int b) {
        return a + b;
    };
    
    std::cout << "Sum: " << add(5, 3) << "\n";
    
    return 0;
}

输出:

Sum: 8

性能考虑[编辑 | 编辑源代码]

Lambda表达式通常会被编译器内联,因此性能与普通函数相当。但是:

  • 捕获大量变量会增加Lambda对象的大小
  • 使用std::function会有轻微的性能开销
  • 简单的无捕获Lambda可以像函数指针一样高效

总结[编辑 | 编辑源代码]

Lambda表达式是C++中强大的功能,它:

  • 允许在需要的地方定义匿名函数
  • 可以捕获上下文中的变量
  • 语法简洁,适合与STL算法配合使用
  • 在C++14和C++17中得到了进一步扩展

掌握Lambda表达式可以显著提高代码的可读性和表达力,特别是在函数式编程风格和异步编程中。