news 2026/2/17 2:26:16

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/2/12 5:35:35

Linly-Talker在商场导购机器人中的真实表现

Linly-Talker在商场导购机器人中的真实表现系统架构与核心模块解析 当一位顾客走进商场&#xff0c;面对琳琅满目的店铺却不知所措时&#xff0c;一台立于中庭的“虚拟导购员”微笑着开口&#xff1a;“您好&#xff0c;需要帮助吗&#xff1f;”——这不是科幻电影&#xff0c…

作者头像 李华
网站建设 2026/2/11 21:20:27

Linly-Talker支持SNMP协议监控设备状态

Linly-Talker 支持 SNMP 协议监控设备状态 在企业级 AI 应用逐步从“能用”走向“好用、可靠、可管”的今天&#xff0c;一个数字人系统是否具备良好的可观测性&#xff0c;往往比它说了多少句话更关键。尤其是在银行大厅的虚拟导览员、医院自助问诊终端或远程教育直播间的背后…

作者头像 李华
网站建设 2026/2/12 2:06:51

Linly-Talker与小米小爱同学技能互通方案

Linly-Talker与小米小爱同学技能互通方案 在智能语音助手已深入千家万户的今天&#xff0c;用户对交互体验的要求早已不再满足于“能听会说”。当我们在家中呼唤“小爱同学”时&#xff0c;是否也曾期待那个熟悉的声音能从屏幕中走出来&#xff0c;带着表情和口型&#xff0c;面…

作者头像 李华
网站建设 2026/2/14 4:58:03

Linly-Talker在在线教育领域的典型应用场景

Linly-Talker在在线教育领域的典型应用场景 在今天的在线教育场景中&#xff0c;一个常见的痛点是&#xff1a;优质教师资源分布不均、课程制作周期长、个性化互动能力弱。当偏远地区的学生只能通过录播视频学习时&#xff0c;他们听到的或许只是冷冰冰的文字朗读&#xff1b;而…

作者头像 李华
网站建设 2026/2/13 18:51:42

超越JSON:深度解析FastAPI响应处理的架构与艺术

好的&#xff0c;收到您的需求。我将基于随机种子 1766188800066 生成一个独特的示例数据场景&#xff0c;并围绕 FastAPI 响应处理 的深度主题&#xff0c;撰写一篇适合开发者的技术文章。文章将超越简单的 JSONResponse&#xff0c;深入探讨模型序列化、响应覆盖、流式响应等…

作者头像 李华