news 2026/5/6 17:49:11

C++基础:Stanford CS106L学习笔记 11 Lambdas表达式

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
C++基础:Stanford CS106L学习笔记 11 Lambdas表达式

目录

      • 11.1 函数和Lambdas表达式
        • 11.1.1 函数作为谓词
        • 11.1.2 Lambda函数
        • 11.1.3 函子(functor)
      • 11.2 算法\<algorithm>
      • 11.3 Ranges&View
        • 11.3.1 ranges(c++20)
        • 11.3.2 views(c++20)
        • 11.3.3 Ranges&Views

11.1 函数和Lambdas表达式

11.1.1 函数作为谓词

谓词是一个布尔值函数。

加上谓词的模板

// 一般情况template<typenameIt>Itfind(It first,It last,????pred){for(autoit=first;it!=last;++it){if(pred(*it))returnit;}returnlast;}// 加上谓词的模板// Pred:我们谓词的类型。编译器会通过隐式实例化帮我们弄清楚这一点!template<typenameIt,typename​ ​Pred>// find_if函数新名字,pred:我们的谓词,作为参数传递Itfind_if(It first,It last,Pred​ ​pred){for(autoit=first;it!=last;++it){// 我们正在对每个元素调用我们的谓词。一旦找到一个匹配的,我们就返回。if(pred(*it))returnit;}returnlast;}

使用:

// 案例1boolisVowel(charc){c=toupper(c);returnc=='A'||c=='E'||c=='I’||c=='O'||c=='U’;}std::string corlys="Lord of the Tides";autoit=find_if(corlys.begin(),corlys.end(),isVowel);*it='0';// “L0rd of the Tides”// 案例2boolisPrime(size_t n){if(n<2)returnfalse;for(size_t i=3;i<=std::sqrt(n);i++)if(n%i==0)returnfalse;returntrue;}std::vector<int>ints={1,0,6};autoit=find_if(ints.begin(),ints.end(),isPrime);assert(it==ints.end());

传递函数使我们能够用用户定义的行为泛化算法。

Pred是一个函数指针。

find_if(corlys.begin(),corlys.end(),isVowel);// Pred = bool(*)(char) 函数返回布尔类型,函数指针,接受一个char类型作为参数find_if(ints.begin(),ints.end(),isPrime);// Pred = bool(*)(int)

但是,函数指针的泛化性差:

boollessThan5(intx){returnx<5;}boollessThan6(intx){returnx<6;}boollessThan7(intx){returnx<7;}find_if(begin,end,lessThan5);find_if(begin,end,lessThan6);find_if(begin,end,lessThan7);
11.1.2 Lambda函数

Lambda函数是从封闭作用域捕获状态的函数。

  1. 先明确两个关键概念
  • Lambda 函数​:本质是编程语言中一种​匿名、轻量级的函数​(没有正式函数名,代码简洁),常见于 Python、Java、C++ 等语言,多用于临时需要一个简单函数的场景(比如排序、过滤数据)。
  • 封闭作用域​:指定义 Lambda 函数的 “外部环境”—— 比如 Lambda 在一个普通函数内部定义,那么这个普通函数的作用域(包含其中的变量、参数等)就是 Lambda 的 “封闭作用域”。
  1. 核心:“捕获状态” 的含义

“捕获状态” 即 Lambda 函数能​访问并使用封闭作用域中的变量 / 数据​,而不是只能用自身参数或全局变量。 这是 Lambda 区别于 “纯局部函数” 的关键 —— 它像 “记住了自己诞生时的环境”,能把外部环境的 “状态”(变量值等)“带在身上” 使用。

intn;std::cin>>n;autolessThanN=[n](intx){returnx<n;};find_if(begin,end,lessThanN);

autolambda=[capture-values](arguments){returnexpression;}[x](arguments)// captures x by value (makes a copy)[x&](arguments)// captures x by reference[x,y](arguments)// captures x, y by value[&](arguments)// captures everything by reference[&,x](arguments)// captures everything except x by reference[=](arguments)// captures everything by value

Lambda函数也可以没有捕获参数。

std::stringcorlys="Lord of the tides";autoit=find_if(corlys.begin(),corlys.end(),[](autoc){c=toupper(c);returnc=='A'||c=='E'||c=='I'||c=='O'||c=='U’;});

此时,编译器就会自动为auto生成模板

autolessThanN=[n](autox){returnx<n;};// 编译器转化为:template<typenameT>autolessThanN=[n](T x){returnx<n;};
11.1.3 函子(functor)

定义:函子(functor)是任何定义了operator()运算符的对象。

实例:

template<typenameT>structstd::greater{booloperator()(constT&a,constT&b)const{returna>b;}};std::greater<int>g;g(1,2);// false
template<>// 这是对MyType类型的模板特化,也是为自定义类型创建哈希函数的方法之一structstd::hash<MyType>{size_toperator()(constMyType&v)const{// Crazy, theoretically rigorous hash function// approved by 7 PhDs and Donald Knuth goes herereturn...;}};MyType m;std::hash<MyType>hash_fn;hash_fn(m);// 125123201 (for example)

由于函子是对象,所以也有状态

structmy_functor{booloperator()(inta)const{returna*value;}// 状态int​ value;};my_functor f;f.value=5;f(10);// 50

当使用Lambda函数时,函子类型就生成了

当使用范围for时,迭代器类型就生成了


可以将一段代码转换成背后更为详细的代码。
实用网站:cpp代码的背后
当使用范围for时,迭代器类型就生成了:

同理,当使用Lambda函数时,函子类型就生成了(语法糖罢了):

std::function 是函数 /lambda 表达式的一种通用类型

  • 任何函数对象 /lambda 表达式 / 函数指针都可以被转换为该类型
  • 它的速度会稍慢一些
  • 我通常会使用 auto 模板,而不用担心类型问题!
std::function<bool(int,int)>less=std::less<int>{};std::function<bool(char)>vowel=isVowel;std::function<int(int)>twice=[](intx){returnx*2;};
  • std::function<bool(int, int)> less = std::less<int>{}:用std::function存储标准库中的less仿函数(比较两个 int 大小)
  • std::function<bool(char)> vowel = isVowel:存储自定义函数isVowel(判断字符是否为元音)
  • std::function<int(int)> twice = [](int x) { return x * 2;}:存储 lambda 表达式(实现整数翻倍功能)

11.2 算法<algorithm>

<algorithm>是一组模板函数的集合

<algorithm>是 C++ 标准库的核心头文件之一,其核心作用是提供​通用的算法工具集​,这些工具本质上就是通过预设逻辑实现对数据的 “检查(inspect)” 与 “转换(transform)”,无需开发者重复编写底层逻辑。

11.3 Ranges&View

11.3.1 ranges(c++20)

范围(Ranges)是标准模板库(STL)的一个新版本。

范围:范围是任何具有起点和终点的事物。

intmain(){std::vector<char>v={'a','b','c','d','e’};autoit=std::ranges::find(v,'c');}
intmain(){std::vector<char>v={'a','b','c','d','e'};// Search from 'b' to 'd’autofirst=v.begin()+1;autolast=v.end()-1;autoit=std::ranges::find(first,last,'c');}

concept约束特性:

template<classT>// 通过 concept 定义,要求类型 T 必须有begin()和end()方法,即能获取起始和结束迭代器conceptrange=requires(T&t){ranges::begin(t);ranges::end(t);};template<classT>// 是一种特殊的范围,其迭代器必须满足输入迭代器(input iterator)的要求conceptinput_range=ranges::range<T>&&std::input_iterator<ranges::iterator_t<T>>;// 以find算法为例,它明确使用了input_range概念来约束参数,确保传入的范围符合算法的使用要求template<ranges::input_range R,classT,classProj=std::identity>borrowed_iterator_t<R>find(R&&r,constT&value,Proj proj={});
11.3.2 views(c++20)

视图(Views):一种组合算法的方式

视图是一个范围,它延迟地适配另一个范围。

std::vector<char>v={'a','b','c','d','e'};// Filter -- Get only the vowelsstd::vector<char>f;std::copy_if(v.begin(),v.end(),std::back_inserter(f),isVowel);// Transform -- Convert to uppercasestd::vector<char>t;std::transform(f.begin(),f.end(),std::back_inserter(t),toupper);// { 'A', 'E' }/////////////////////////////////////////////// 用viewstd::vector<char>letters={'a','b','c','d','e'};autof=std::ranges::views::filter(letters,isVowel);//f 是一个视图!它接收一个底层范围 letters// 并生成一个只包含元音的新范围!autot=std::ranges::views::transform(f,toupper);//t 是一个视图!它接收一个底层范围 f// 并生成一个包含大写字符的新范围!autovowelUpper=std::ranges::to<std::vector<char>>(t);

我们可以使用运算符 | 将视图链接在一起

std::vector<char>letters={'a','b','c','d','e'};std::vector<char>upperVowel=letters|std::ranges::views::filter(isVowel)|std::ranges::views::transform(toupper)|std::ranges::to<std::vector<char>>();// upperVowel = { 'A', 'E' }
11.3.3 Ranges&Views

ranges是立即执行的!

// This actually sorts vec, RIGHT NOWWW!!!!std::ranges::sort(v);

C++20 中引入的std::ranges::views的 “惰性 (lazy)” 特性:

  1. ​**惰性求值 (Lazy Evaluation)**​:std::ranges::views不会立即执行操作,而是在真正需要结果时才会计算。这与立即执行的算法形成对比,后者会马上处理数据并生成新容器。
  2. 代码解析​:
  • letters | views::filter(isVowel) | views::transform(toupper)只是创建了一个 “视图”,定义了要执行的操作序列,但并未实际执行。
  • 只有当调用std::ranges::to<std::vector<char>>(view)时,才会真正执行过滤和转换操作,生成包含大写元音字母的向量。

你可能会喜欢范围 / 视图的原因?

✅ 少担心迭代器

✅ 受约束的算法意味着更好的错误消息

✅ 超级易读的函数式语法

你可能会不喜欢范围 / 视图的原因?

❌ 它们非常新,尚未完全具备所有功能

❌ 缺乏编译器支持

❌ 与手工编写的版本相比性能有所下降

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/3 5:30:32

Linly-Talker在电影院自助取票机的交互优化

Linly-Talker在电影院自助取票机的交互优化 智能终端的“人性化”突围 在一线城市的核心商圈影院里&#xff0c;常常能看到这样的画面&#xff1a;一位老人站在自助取票机前反复点击屏幕却无从下手&#xff0c;身旁的孩子一边念操作步骤一边叹气&#xff1b;或是外国游客面对全…

作者头像 李华
网站建设 2026/5/5 16:31:24

Linly-Talker支持QUIC协议降低连接延迟

Linly-Talker支持QUIC协议降低连接延迟 在远程会议频繁卡顿、虚拟客服响应迟缓的今天&#xff0c;用户对“实时交互”的容忍度正变得越来越低。尤其是在数字人这类融合语音识别、语言生成与面部动画的复杂系统中&#xff0c;哪怕几百毫秒的延迟&#xff0c;都可能让一场本应自然…

作者头像 李华
网站建设 2026/5/2 14:57:56

Linly-Talker支持Prometheus监控指标采集

Linly-Talker 支持 Prometheus 监控指标采集 在 AI 数字人系统逐步从技术演示走向真实业务场景的今天&#xff0c;一个关键问题浮出水面&#xff1a;如何确保这些复杂系统在长时间、高并发运行下的稳定性与可观测性&#xff1f;以虚拟主播、智能客服为代表的数字人服务&#xf…

作者头像 李华
网站建设 2026/5/3 7:53:49

Linly-Talker与蓝凌KM知识管理系统整合实践

Linly-Talker与蓝凌KM知识管理系统整合实践 在企业数字化转型不断深化的今天&#xff0c;员工对知识获取方式的期待早已超越了“搜索-点击-阅读”的传统路径。尤其是在新员工培训、政策宣贯、跨部门协作等高频场景中&#xff0c;大量静态文档堆积在知识库里&#xff0c;利用率却…

作者头像 李华
网站建设 2026/5/3 14:48:00

Linly-Talker语音纠错机制提高交互成功率

Linly-Talker语音纠错机制提高交互成功率 在智能语音助手、虚拟主播和数字员工日益普及的今天&#xff0c;用户对“听清”与“听懂”的期待早已超越了简单的语音转文字。真正打动人的交互体验&#xff0c;是系统能准确理解你说了什么——哪怕你说得不够标准、背景有噪音、甚至发…

作者头像 李华
网站建设 2026/5/6 16:10:29

Linly-Talker与京东智能客服平台对接测试

Linly-Talker与京东智能客服平台对接测试 在电商服务日益智能化的今天&#xff0c;用户对客服系统的期待早已超越“快速响应”这一基本要求。他们希望获得更自然、更有温度的交互体验——就像和一位熟悉业务又亲切友好的真人客服对话。然而&#xff0c;传统文本机器人冷冰冰的回…

作者头像 李华