通知图标

欢迎访问津桥芝士站

Lambda 表达式(3)

来自AI助手的总结
C++ Lambda表达式通过捕获初始化、mutable关键字、返回值类型推导等高级用法,展现了其在现代编程中的灵活性与强大功能。

1. Lambda 表达式的高级用法

1.1 捕获初始化

C++14 引入了 Lambda 表达式捕获初始化(capture initialization),允许你在捕获列表中直接初始化工厂函数。这使得可以在 Lambda 中捕获和初始化变量。

#include <iostream>

int main() {
    int a = 10;
    
    // 使用捕获初始化
    auto lambda = [b = a + 5]() {
        std::cout << "b = " << b << std::endl; // b 在捕获时初始化为 a + 5
    };

    lambda();  // 输出: b = 15
    return 0;
}

1.2 使用 mutable 关键字

默认情况下,Lambda 捕获的变量(通过引用或值)是常量的。如果你想在 Lambda 函数内修改捕获的变量,需要使用 mutable 关键字。

#include <iostream>

int main() {
    int x = 10;

    auto lambda = [x]() mutable {
        x += 5;
        std::cout << "Inside lambda: " << x << std::endl; // 输出: 15
    };

    lambda();
    std::cout << "Outside lambda: " << x << std::endl; // 输出: 10 (x 仍然是 10)
    return 0;
}

1.3 Lambda 返回值类型推导

在某些情况下,你可能希望明确地指定 Lambda 的返回类型,特别是当有多个返回路径并且编译器无法推导出返回类型时。可以使用尾返回类型(trailing return type)来指定。

#include <iostream>

int main() {
    auto lambda = [](int x, int y) -> int {
        return x + y;
    };

    std::cout << "Sum: " << lambda(3, 4) << std::endl; // 输出: Sum: 7
    return 0;
}

1.4 参数包与变长参数

你可以利用 Lambda 表达式的参数包特性来处理可变参数列表。这在现代 C++ 中与特征匹配(template metaprogramming)一起使用非常方便。

#include <iostream>
#include <initializer_list>

auto sum = [](std::initializer_list<int> list) {
    int total = 0;
    for (auto value : list) {
        total += value;
    }
    return total;
};

int main() {
    std::cout << "Sum: " << sum({1, 2, 3, 4, 5}) << std::endl; // 输出: Sum: 15
    return 0;
}

2. 不常见的 Lambda 语法

2.1 关联状态的 Lambda

可以在 Lambda 表达式中存放状态和行为。可以通过捕获语法来维护状态信息。这在某些需要保持状态的回调函数中很有用。

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

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

    // 以状态保持为目标的 Lambda
    std::sort(nums.begin(), nums.end(), [count = 0](int a, int b) mutable {
        count++;
        std::cout << "Comparison count: " << count << std::endl;
        return a < b;
    });

    for (int num : nums) {
        std::cout << num << " "; // 输出: 1 2 3 4 5 
    }
    std::cout << std::endl;

    return 0;
}

2.2 递归 Lambda

C++14 允许 Lambda 是可递归的,通过捕获自身的方式来实现这一点。

#include <iostream>

int main() {
    // 递归 Lambda 计算阶乘
    std::function<int(int)> factorial = [](int n) -> int {
        return (n <= 1) ? 1 : n * factorial(n - 1);
    };

    int result = factorial(5);
    std::cout << "Factorial of 5: " << result << std::endl; // 输出: Factorial of 5: 120
    return 0;
}

2.3 Lambda 作为模板参数

在 C++20 中,Lambda 可以作为模板参数,支持更灵活的编程模式。你可以在模板中直接使用 Lambda。

#include <iostream>

template<typename Func>
void applyLambda(Func func) {
    func();
}

int main() {
    auto myLambda = []() { std::cout << "Hello, Lambda as template argument!" << std::endl; };

    applyLambda(myLambda); // 输出: Hello, Lambda as template argument!
    return 0;
}

2.4 Lambda 与 std::bind 结合

可以将 Lambda 与 std::bind 结合使用,在处理复杂的回调时使代码更加灵活。

#include <iostream>
#include <functional>

int main() {
    auto add = [](int x, int y) { return x + y; };
    auto boundAdd = std::bind(add, std::placeholders::_1, 10); // 绑定第二个参数为 10

    std::cout << "Result: " << boundAdd(5) << std::endl; // 输出: Result: 15
    return 0;
}

最后

Lambda 函数在现代 C++ 中是一个非常强大的特性,通过灵活的捕获机制和多种不常见的语法选项,Lambda 能够实现许多高效灵活的编程风格。从捕获初始化到递归调动,Lambda 的高级用法完全展现了其灵活与强大的潜力。

使用 Lambda,你可以将程序逻辑更加模块化和透明,为代码加上更清晰的语义。随着 C++ 的不断发展,Lambda 函数及其相关特性的增多,程序员有了更多的工具来编写简洁且高效的代码。

请登录后发表评论

    没有回复内容