c++ Lambda 表达式使用笔记

c++ Lambda 表达式使用笔记

      • Lambda 表达式的基本组成部分
        • 1. **捕获列表(Capture List)**
        • 2. **参数列表(Parameters)**
        • 3. **返回类型(Return Type)**
        • 4. **函数体(Function Body)**
        • 5. **说明符(Specifiers)**
        • 6. **模板形参(C++20)**
      • Lambda 表达式的深入应用
        • 1. **即调用函数表达式(IIFE)**
        • 2. **捕获时计算(C++14)**
        • 3. **使用 `auto` 避免复制(C++14)**
        • 4. **Lifting(C++14)**
        • 5. **递归调用(C++14)**
      • 使用注意事项
      • 深入应用举例
        • 1. **IIFE 用于初始化**
        • 2. **捕获时计算**
        • 3. **Lifting 示例**
        • 4. **递归调用示例**

Lambda 表达式的基本组成部分

Lambda 表达式是 C++11 引入的一种匿名函数,用于定义轻量级的可调用对象。它的基本语法如下:

[capture](parameters) -> return_type {
    // 函数体
}
1. 捕获列表(Capture List)

捕获列表用于指定 lambda 表达式如何访问外部作用域的变量。捕获方式包括:

  • 值捕获:捕获外部变量的副本。
  • 引用捕获:捕获外部变量的引用。
  • 混合捕获:同时使用值捕获和引用捕获。
  • this 捕获:捕获当前对象的 this 指针。
  • 初始化捕获(C++14):在捕获列表中直接初始化变量。
  • *this 捕获(C++17):捕获当前对象的副本。

示例:

int x = 10;
int y = 20;

// 值捕获
auto lambda1 = [x]() { return x; }; // x 被复制到 lambda 中

// 引用捕获
auto lambda2 = [&y]() { return y; }; // y 被引用捕获

// 混合捕获
auto lambda3 = [x, &y]() { return x + y; }; // x 被复制,y 被引用

// this 捕获
struct MyClass {
    int value = 42;
    auto get_lambda() {
        return [this]() { return value; }; // 捕获 this 指针
    }
};

// 初始化捕获(C++14)
auto lambda4 = [z = x + y]() { return z; }; // z 被初始化为 x + y

// *this 捕获(C++17)
auto lambda5 = [*this]() { return value; }; // 捕获当前对象的副本
2. 参数列表(Parameters)

参数列表与普通函数的参数列表类似,用于定义 lambda 表达式的输入参数。

示例:

auto add = [](int a, int b) { return a + b; };
std::cout << add(3, 4); // 输出 7
3. 返回类型(Return Type)

返回类型可以显式指定,也可以由编译器自动推导。如果函数体只有一条 return 语句,编译器可以自动推导返回类型。

示例:

// 自动推导返回类型
auto square = [](int x) { return x * x; };

// 显式指定返回类型
auto cube = [](int x) -> int { return x * x * x; };
4. 函数体(Function Body)

函数体是 lambda 表达式的实现部分,包含具体的逻辑代码。

示例:

auto print = [](const std::string& msg) {
    std::cout << msg << std::endl;
};
print("Hello, Lambda!");
5. 说明符(Specifiers)
  • mutable:允许修改值捕获的变量。
  • constexpr(C++17):将 lambda 表达式声明为常量表达式。
  • consteval(C++20):将 lambda 表达式声明为立即求值的常量表达式。

示例:

// mutable 示例
int a = 10;
auto lambda_mutable = [a]() mutable { a++; return a; };
std::cout << lambda_mutable(); // 输出 11,但外部的 a 仍然是 10

// constexpr 示例(C++17)
constexpr auto lambda_constexpr = [](int x) constexpr { return x * x; };
static_assert(lambda_constexpr(5) == 25); // 编译时计算

// consteval 示例(C++20)
consteval auto lambda_consteval = [](int x) consteval { return x * x; };
static_assert(lambda_consteval(5) == 25); // 编译时计算
6. 模板形参(C++20)

C++20 允许 lambda 表达式使用模板形参。

示例:

auto generic_lambda = []<typename T>(T x) { return x * x; };
std::cout << generic_lambda(5) << std::endl;    // 输出 25
std::cout << generic_lambda(3.14) << std::endl; // 输出 9.8596

Lambda 表达式的深入应用

1. 即调用函数表达式(IIFE)

IIFE 是一种在定义 lambda 表达式后立即调用的技术,通常用于限制变量的作用域。

示例:

int result = [](int a, int b) { return a + b; }(3, 4);
std::cout << result; // 输出 7
2. 捕获时计算(C++14)

在捕获列表中直接初始化变量,可以在捕获时进行计算。

示例:

int x = 10;
int y = 20;
auto lambda = [z = x + y]() { return z; };
std::cout << lambda(); // 输出 30
3. 使用 auto 避免复制(C++14)

在捕获列表中使用 auto 可以避免显式指定类型,同时避免不必要的复制。

示例:

std::string msg = "Hello";
auto lambda = [msg = std::move(msg)]() { return msg; };
std::cout << lambda(); // 输出 "Hello"
4. Lifting(C++14)

Lifting 是指将 lambda 表达式提升为函数对象,以便在更广泛的上下文中使用。

示例:

auto make_adder = [](int x) {
    return [x](int y) { return x + y; };
};
auto add5 = make_adder(5);
std::cout << add5(10); // 输出 15
5. 递归调用(C++14)

Lambda 表达式可以通过 std::function 实现递归调用。

示例:

std::function<int(int)> factorial = [&](int n) {
    return n <= 1 ? 1 : n * factorial(n - 1);
};
std::cout << factorial(5); // 输出 120

使用注意事项

  1. 捕获列表的作用
    • 值捕获会复制变量,引用捕获会共享变量。
    • 避免在 lambda 表达式中修改值捕获的变量,除非使用 mutable
  2. 性能问题
    • 引用捕获可能导致悬空引用,尤其是在异步编程中。
    • 值捕获可能导致不必要的复制,尤其是对于大型对象。
  3. 生命周期问题
    • 确保 lambda 表达式中引用的对象在调用时仍然有效。
  4. 递归调用的限制
    • 直接递归调用 lambda 表达式需要借助 std::function 或其他机制。

深入应用举例

1. IIFE 用于初始化
int x = [] {
    int a = 10;
    int b = 20;
    return a + b;
}();
std::cout << x; // 输出 30
2. 捕获时计算
int a = 10;
int b = 20;
auto lambda = [sum = a + b]() { return sum; };
std::cout << lambda(); // 输出 30
3. Lifting 示例
auto make_multiplier = [](int factor) {
    return [factor](int x) { return x * factor; };
};
auto double_value = make_multiplier(2);
std::cout << double_value(5); // 输出 10
4. 递归调用示例
std::function<int(int)> fibonacci = [&](int n) {
    return n <= 1 ? n : fibonacci(n - 1) + fibonacci(n - 2);
};
std::cout << fibonacci(10); // 输出 55

你可能感兴趣的:(C++,c++,笔记)