news 2026/4/16 13:45:50

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/4/16 3:35:36

【Open-AutoGLM新应用适配全攻略】:掌握5大核心流程,快速实现AI模型落地

第一章&#xff1a;Open-AutoGLM新应用适配概述Open-AutoGLM 是一个面向自动化自然语言理解与生成任务的开源框架&#xff0c;支持快速集成大语言模型至垂直领域应用。其核心优势在于模块化解耦、接口标准化以及对多后端模型的良好兼容性&#xff0c;使得开发者能够高效完成从原…

作者头像 李华
网站建设 2026/4/15 8:16:49

Linly-Talker语音变声功能保护用户身份

Linly-Talker语音变声功能保护用户身份 在虚拟主播直播带货、智能客服24小时在线、AI教师远程授课的今天&#xff0c;数字人早已不再是科幻电影中的概念。但当你的声音被录下、建模、复现时&#xff0c;你是否想过——那个“像你”的声音&#xff0c;会不会反过来成为识别你身份…

作者头像 李华
网站建设 2026/4/14 11:57:42

Linly-Talker支持CoAP轻量级物联网协议

Linly-Talker 支持 CoAP 轻量级物联网协议 在智能家居、工业边缘计算和分布式数字人系统日益普及的今天&#xff0c;一个核心问题逐渐浮现&#xff1a;如何让 AI 驱动的复杂应用——比如实时语音交互的虚拟助手——在树莓派这类资源受限设备上稳定运行&#xff1f;更进一步&am…

作者头像 李华
网站建设 2026/4/16 8:03:47

Linly-Talker实现语音指令控制智能家居

Linly-Talker&#xff1a;让智能家居“看得见”你的声音 在客厅里轻声说一句“今天好累&#xff0c;能调暗点灯吗”&#xff0c;屏幕中的虚拟管家微微点头&#xff0c;眼神关切地回应&#xff1a;“已经为您切换到放松模式&#xff0c;灯光已调至暖黄。”随即&#xff0c;房间里…

作者头像 李华
网站建设 2026/4/16 13:02:10

Linly-Talker降低数字人成本90%以上

Linly-Talker&#xff1a;如何用一张照片和一段文字&#xff0c;生成会说话的数字人 在电商直播间里&#xff0c;一个面容亲和、口齿清晰的“虚拟主播”正用标准普通话介绍着新款护肤品&#xff0c;语气自然、唇形精准&#xff0c;仿佛真人出镜。可实际上&#xff0c;这个“主播…

作者头像 李华