c++ lamda(三)Lambda表达式

上一篇讲道的函数对象,虽然可以传递状态,但是得创建一个对象并重写operator方法,略显麻烦

Lambda就是来解决这个痛点的。Lambda 表达式就是一个能直接写在代码里、当场定义的小函数,不用先起名字、不用单独定义。它的形式是:

复制代码
[捕获列表](参数列表) mutable(可选) noexcept(可选) -> 返回类型(可选) {
    函数体
}

瞬间懵逼,这都是些什么玩意呀

别被这一长串吓到。实际开发中,大部分时候你只需要前三个部分:捕获列表、参数列表、函数体。后面的都是锦上添花。

咱们拆开来看:

  • 捕获列表:决定Lambda能访问外部哪些变量。这是Lambda最核心的设计。
  • 参数列表:和普通函数一样,传参用。
  • mutable:默认情况下,Lambda的operator()是const的。加上mutable,你就可以修改捕获的副本了。
  • noexcept:声明这个Lambda不会抛异常。
  • 返回类型:大部分情况下编译器能自动推导,不用写。

直接看一段简单的代码吧

cpp 复制代码
#include <iostream>
#include <functional>

int main() {
    int threshold = 10;
    std::function<bool(int)> isBig = [threshold](int x) mutable noexcept -> bool {return x > threshold;};

    std::cout << isBig(15) << '\n';   // 输出 1
    return 0;
}

觉得std::function<bool(int)>很长的话可以用auto代替

像这样

cpp 复制代码
#include <iostream>

int main() {
    int threshold = 10;
    auto isBig = [threshold](int x) mutable noexcept -> bool {return x > threshold;};
    std::cout << isBig(15) << '\n';   // 输出 1(true)
    return 0;
}

运行结果

cpp 复制代码
1

各项含义:

  • [threshold]:捕获列表,按值捕获 threshold(闭包内持有一份副本)。

  • (int x):参数列表。

  • mutable:允许在函数体内修改按值捕获的副本(本例没修改,所以可省)。

  • noexcept:声明该 lambda 不抛异常(本例可省)。

  • -> bool:显式指定返回类型(本例可省,编译器自动推导为 bool)。

  • { return x > threshold; }:函数体。

可以简化成下面这样,结果是一样的

cpp 复制代码
#include <iostream>

int main() {
    int threshold = 10;
    auto isBig = [threshold](int x) { return x > threshold; };   // 捕获 threshold
    std::cout << isBig(15) << '\n';   // 输出 1(true)
    return 0;
}

常见用法:直接当参数传

cpp 复制代码
#include <iostream>
#include <vector>
#include <algorithm>

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

    std::sort(v.begin(), v.end(), [](int a, int b) {   // 当场写一个比较函数传进去
        return a > b;                                   // 降序
    });

    for (int x : v) std::cout << x << ' ';              // 输出 5 4 3 1 1
    std::cout << '\n';
    return 0;
}

运行结果

cpp 复制代码
5 4 3 1 1 

这里有个小疑问,std::sort的第三个参数是什么?

它的函数原型是这样的

cpp 复制代码
void sort(RandomIt first, RandomIt last, Compare comp);

Compare的函数签名大概是这样

bool(const T&, const T&)

标准对 Compare 的要求不是"必须精确写成 bool(const T&, const T&)",而是:

对于解引用迭代器得到的类型 T,comp 必须能用两个 T 类型的实参调用 ,且返回值可转换为 bool。

也就是说,下面这些都能作为 comp:

cpp 复制代码
bool f1(int a, int b);                    // 按值
bool f2(const int& a, const int& b);      // 按 const 引用
struct C { bool operator()(int a, int b) const; };
auto l = [](int a, int b){ return a < b; };

自己实现一个接收lamda表达式的方法

把可调用物的类型做成模板参数,这样能接受函数指针、函数对象、lambda 等任何可调用物,且零开销(编译期确定,无类型擦除):

cpp 复制代码
#include <iostream>
#include <vector>

// Func 是任意可调用物,action 是它的一个实例
template<typename Func>
void myforEach(const std::vector<int>& v, Func action) {
    for (int x : v) {
        action(x);          // 调用传进来的可调用物
    }
}

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

    // 传函数对象
    struct Print { void operator()(int x) const { std::cout << x << ' '; } };
    myforEach(v, Print{});
    std::cout << '\n';

    // 传 lambda
    int sum = 0;
    myforEach(v, [&sum](int x){ sum += x; });
    std::cout << "sum = " << sum << '\n';   // sum = 6

    return 0;
}

运行结果

cpp 复制代码
1 2 3 
sum = 6

关于lamda还有一些知识点,就留在下一篇继续讲解吧

上一篇:c++ lamda(二)没有lamda前如何传递可执行代码作为参数

相关推荐
头发还在的女程序员8 分钟前
Java在线租房系统源码解析:Spring Boot+Vue 3+UniApp房源管理与预约看房方案
java·vue.js·spring boot·租房小程序·租房系统·租房软件
zhanlang021711 分钟前
HTML 零基础入门到企业实战【第五章 5.4】内嵌网页 iframe 标签:嵌入网页、视频、地图实战
前端·html·音视频
FYKJ_201016 分钟前
springboot同人周边订单管理系统48955-计算机毕业设计、课程设计
java·javascript·vue.js·spring boot·django·php·课程设计
Flynn Liang39 分钟前
LLM 应用安全:Prompt 注入、越权与输入输出护栏
java·人工智能·大模型·langchain4j·llm 安全·prompt 注入·guardrail
特立独行的猫A7 小时前
用仓颉语言 cj-tauri 框架,五分钟给娃做了个鸿蒙形近字游戏
java·后端·python
2分钟速写快排8 小时前
孔乙己的茴字有多少种写法?|AI 对话实时通信的三种实现
前端·javascript·github
Penge66610 小时前
JavaScript:BOM 详解
前端
Penge66610 小时前
Vite vs Webpack:前端构建工具原理与实战
前端
Penge66610 小时前
前端包管理工具:npm、Yarn、pnpm 快速入门
前端