C++11(三)———AI对话学习笔记(自用)

\[\] 什么都不捕捉

x x 按值捕捉

\&x x 按引用捕捉

= 默认全部按值捕捉

\& 默认全部按引用捕捉

=, \&x 默认值捕捉,但 x 引用捕捉

\&, x 默认引用捕捉,但 x 值捕捉

OLambda 最大的意义:减少"样板代码"

这个词你以后会经常遇到:

样板代码(boilerplate code)

比如为了实现一个简单比较:

复制代码
cpp 复制代码
class GreaterThan
{
public:
    GreaterThan(int x)
        : _x(x)
    {}

    bool operator()(int val) const
    {
        return val > _x;
    }

private:
    int _x;
};

实际上你真正想表达的逻辑只有:

复制代码
return val > x;

Lambda 让你直接写这个逻辑:

复制代码
[x](int val)
{
    return val > x;
}

所以 Lambda 的核心价值不是:

"我比仿函数更强。"

而是:

"我不想为了一个临时的小逻辑,专门创建一个类。"


4. 你可以把它理解成"匿名仿函数"

这个关系非常重要:

复制代码
复制代码
仿函数
↓
需要自己写一个类
↓
需要自己写 operator()
↓
创建对象
↓
使用

而 Lambda:

复制代码
Lambda
↓
编译器帮你生成那个匿名类
↓
编译器帮你生成 operator()
↓
编译器帮你创建对象
↓
你直接使用

find_if 怎么找到大于 3 的数?"

因为它内部:

复制代码
while (first != last)
{
    if (pred(*first))
        return first;

    ++first;
}

"Lambda 在里面干什么?"

它只负责:

复制代码
复制代码
return x > 3;

对,你现在问到的是 Lambda 最核心的一个问题

auto f = [x](int y){ return x + y; };

这里 Lambda 到底是什么东西 ?为什么可以直接赋值给 auto f,而不是非得传给 sortfind_if 这种函数?

答案是:

Lambda 表达式本身会产生一个"函数对象",这个对象可以先被保存到变量里。auto 只是帮你推导这个匿名对象的类型。

我们一步一步来。


1. 先看最普通的变量赋值

你熟悉:

复制代码
int x = 10;

这里发生了什么?

复制代码
10
↓
一个 int 类型的值
↓
保存到 x

所以:

复制代码
cout << x;

就是使用这个变量。


现在看:

复制代码
auto f = [x](int y)
{
    return x + y;
};

这里的思想其实非常类似:

复制代码
Lambda表达式
     ↓
产生一个函数对象
     ↓
这个对象保存到 f

所以 f 不是一个普通函数

f 是一个对象


2. 这就是为什么 auto 非常重要

你自己根本没办法轻松写出这个 Lambda 的类型。

比如:

复制代码
auto f = [x](int y)
{
    return x + y;
};

这个 Lambda 的类型是编译器生成的一个唯一的、匿名的闭包类型(closure type)

你不知道它叫什么。

所以你没法写:

复制代码
??? f = [x](int y)
{
    return x + y;
};

这个 ??? 是什么?

你不知道。

所以 C++ 给了你:

复制代码
auto

让编译器自己推导。

也就是:

复制代码
auto f = Lambda对象;

编译器自己知道:

复制代码
f 的类型 = 这个 Lambda 对应的匿名类型

3. 你可以把它粗略翻译成一个类

比如:

复制代码
int x = 10;

auto f = [x](int y)
{
    return x + y;
};

编译器可以近似理解为

复制代码
class Lambda
{
public:
    Lambda(int x)
        : _x(x)
    {}

    int operator()(int y) const
    {
        return _x + y;
    }

private:
    int _x;
};

然后:

复制代码
Lambda f(x);

注意:

这里的 Lambda 只是为了帮助你理解。

真实情况下编译器生成的类没有这个名字给你使用。

所以我们才写:

复制代码
auto f = ...

4. 那 f 到底是什么?

现在非常明确:

复制代码
int x = 10;

auto f = [x](int y)
{
    return x + y;
};

可以理解成:

复制代码
f
│
│  是一个对象
↓
┌─────────────────┐
│ Lambda对象       │
│                 │
│ _x = 10         │
│                 │
│ operator()(y)   │
└─────────────────┘

所以:

复制代码
f(20);

为什么可以调用?

因为:

复制代码
f(20);

本质:

复制代码
f.operator()(20);

最后:

复制代码
return 10 + 20;

得到:

复制代码
30

5. 那为什么 Lambda 不一定非得传给 sort

这个问题非常好。

因为 Lambda 本身不是"只能传给 STL 函数的东西"

它就是一个对象。

既然是对象,那么当然可以:

直接保存

复制代码
auto f = [](int x)
{
    return x * 2;
};

直接调用

复制代码
cout << f(10);

传给其他函数

复制代码
someFunction(f);

直接作为参数

复制代码
sort(v.begin(), v.end(),
     [](int a, int b)
     {
         return a > b;
     });

这些都是可以的。


6. 你可以把 Lambda 想成"临时制造对象"

比如:

复制代码
auto f = [](int x)
{
    return x * 2;
};

就像你写:

复制代码
class A
{
public:
    int operator()(int x)
    {
        return x * 2;
    }
};

A f;

然后:

复制代码
f(10);

所以 Lambda 只是帮你省掉了:

复制代码
class A
{
public:
    ...
};

这些麻烦的东西。


7. 为什么传给 sort 的时候看起来不一样?

你之前看到:

复制代码
sort(v.begin(), v.end(),
     [](int a, int b)
     {
         return a > b;
     });

这里 Lambda 没有写:

复制代码
auto f =

是不是感觉不一样?

其实完全一样

你完全可以写成:

复制代码
auto cmp = [](int a, int b)
{
    return a > b;
};

sort(v.begin(), v.end(), cmp);

这两个是一个意思。


写法一:直接传

复制代码
sort(v.begin(), v.end(),
     [](int a, int b)
     {
         return a > b;
     });

相当于:

复制代码
创建一个 Lambda 对象
        ↓
直接把对象传给 sort

写法二:先保存

复制代码
auto cmp = [](int a, int b)
{
    return a > b;
};

sort(v.begin(), v.end(), cmp);

相当于:

复制代码
创建 Lambda 对象
        ↓
保存到 cmp
        ↓
把 cmp 传给 sort

所以你现在应该明白:

Lambda 可以直接传,也可以先保存。


8. 这和普通函数也很像

比如:

复制代码
int Add(int a, int b)
{
    return a + b;
}

你可以直接:

复制代码
cout << Add(1, 2);

也可以把函数的地址传给别的函数。

Lambda 则更像是:

复制代码
"我现场造一个函数对象。"

然后你可以:

复制代码
现场使用
↓
或者
↓
先保存下来
↓
以后再使用

9. 最关键的区别:Lambda 是"表达式"

你现在看到:

复制代码
[x](int y)
{
    return x + y;
}

不要把它单纯看成:

"这是一个函数。"

更准确地说:

这是一个 Lambda 表达式,它产生一个闭包对象。

所以:

复制代码
auto f = [x](int y)
{
    return x + y;
};

可以理解成:

复制代码
Lambda表达式
     ↓
创建闭包对象
     ↓
赋值给 f

而这个闭包对象内部:

复制代码
保存 x
+
拥有 operator()

所以它既:

有状态(捕捉的变量)

又:

可以像函数一样调用

这就是 Lambda 的厉害之处。


10. 你现在把这两个例子对照看

直接给 sort

复制代码
sort(v.begin(), v.end(),
     [](int a, int b)
     {
         return a > b;
     });

相当于:

复制代码
创建 Lambda 对象
      ↓
直接交给 sort

先保存

复制代码
auto cmp = [](int a, int b)
{
    return a > b;
};

sort(v.begin(), v.end(), cmp);

相当于:

复制代码
创建 Lambda 对象
      ↓
保存到 cmp
      ↓
cmp 本身就是一个函数对象
      ↓
交给 sort

你现在最应该记住这一句话 🧠

Lambda 不是"只能传给函数的东西",Lambda 表达式本身会创建一个匿名的函数对象。这个对象可以被 auto 保存,也可以直接作为参数传给 sortfind_if 等函数。

所以:

复制代码
auto f = [x](int y)
{
    return x + y;
};

实际上就是:

复制代码
         Lambda表达式
              ↓
       创建一个匿名对象
              ↓
       ┌─────────────┐
       │ f            │
       │              │
       │ 保存 x       │
       │ operator()   │
       └─────────────┘
              ↓
          f(20)
              ↓
      f.operator()(20)

这一下你就把 "Lambda → 闭包对象 → auto → 仿函数 → operator()" 全串起来了。这个链条理解了,C++11 Lambda 基本就真正入门了。

相关推荐
qz_Serene44 分钟前
C++:类和对象(上)
开发语言·c++
weixin_446260852 小时前
AVA-Encoder:面向智能体原生视频表征学习框架
学习·音视频
DeviceHub2 小时前
硬件工程师选型笔记:ALPS SKPMAPE010 与 Tonevee TS-3025 贴片轻触开关 PIN TO PIN 评估指南
笔记
吃好睡好便好2 小时前
说说口罩的佩戴
学习·生活·口罩
郝学胜-神的一滴2 小时前
干货版《算法导论》17:二叉树核心原理、遍历逻辑与高阶实操全解
数据结构·c++·python·算法·计算机·编程
hetao17338372 小时前
2026-08-09~08-14 hetao1733837 的刷题记录
c++·算法
fīɡЙtīиɡ ℡3 小时前
大模型结构化输出
人工智能·学习
疯狂打码的少年3 小时前
【数据结构】二叉树的性质(五大性质+计算)
数据结构·笔记·算法
Dave1205463 小时前
Day17:Agent Memory高级设计——短期记忆、长期记忆与向量语义记忆
人工智能·学习
小唔w3 小时前
2026年AI培训行业观察:主流学习渠道一览
人工智能·学习