16 | 函数对象和lambda:进入函数式编程
该思维导图由 AI 生成,仅供参考
C++98 的函数对象
- 深入了解
- 翻译
- 解释
- 总结
函数对象和lambda表达式是C++中函数式编程的重要概念。函数对象可以被当作函数来使用,而lambda表达式则是一种匿名函数,可以在需要时立即求值。它们的使用可以简化代码,提升性能并使代码更清晰。变量捕获和泛型lambda表达式是lambda表达式中的重要细节,增加了可组合性。此外,`bind`模板和`function`模板在泛型编程和函数式编程中发挥着重要作用。总的来说,函数对象和lambda表达式可以使代码更简洁、更灵活。读者可以通过本文了解函数式编程中的重要概念,并掌握相关技术特点,从而在实际编程中更加灵活运用。
《现代 C++ 编程实战》,新⼈⾸单¥59
全部留言(24)
- 最新
- 精选
- zhengfan吴老师,您好。 四刷本讲。 我对您文中的这一句介绍有点好奇,“每个 lambda 表达式都有一个全局唯一的类型”。 请问这是怎么做到的?本质上不应该是一个函数指针么?这么规定的目的是什么?
作者回复: 还真不是函数指针。可以认为编译器帮你组合出了一个唯一的类型名称吧。 举一个例子,如果你写: auto adder = [n](int x) { return n + x; }; 编译器产生的代码类似于: struct lambda_1266ab7e { lambda_1266ab7e(int n) : n_{n} {} auto operator()(int x) const { return n_ + x; } private: int n_; }; auto adder = lambda_1266ab7e(n);
2020-07-1030 - 廖熊猫老师新年快乐。 lambda表达式大概是生成了一个匿名的struct吧,实现了operator(), 捕获的话对应struct上的字段。
作者回复: 新年快乐。 对,概念上就是这样。
2020-01-0216 - tt1、感觉lambda表达式就是C++中的闭包。 2、lambda表达式可以立即进行求职,这一点和JavaScript里的立即执行函数(Imdiately Invoked Function Expression,IIFE)一样。在JavaScript里,它是用来解决作用域缺陷的。 感觉在动态语言里被用到极致的闭包等特性,因为C++的强大、完备,在C++里很普通。 lambda的定义对应一个匿名函数对象,捕获就是构造这个对象时某种方式的初始化过程,用lambda表达式隐藏了这个过程,只保留了这个意思,更直观和写意。 老师,我对协程很感兴趣,C++会有协程么?隐约感觉捕获变量这个东西是不是可以用在实现协程上? 最后,祝老师新年快乐!
作者回复: 对,就是闭包。 Stackful 协程见 Boost.Coroutine2。Stackless 协程已经进入 C++20,第 30 讲讨论。🤓 新年快乐!
2020-01-029 - tt老师,回过头来看得时候,遇到了一个问题。 在用LAMBDA表达式解决多重初始化路径的问题时,说到这样还可以提高性能,因为不需要默认构造和不需要拷贝/移动。可是在第10讲中讲返回值优化的时候,不是说如果返回值时有条件判断,编译器都被会难倒,从而导致NRVO失效么(函数getA_duang)?
作者回复: 注意我这儿用的是 return Obj(…) 的形式,不是有名变量的返回(Obj a{…} 然后 再 return a),不属于 named return value optimization 的情况。NRVO 指的是本地变量的返回。C++17 开始,prvalue 从语言上作了特殊解释,要求这样的返回直接构造到目的位置。
2020-02-1425 - 总统老唐2020第一课,吴老师新年好
作者回复: 谢谢🙏。在这儿也顺祝所有的同学们新年好!😇🎈🎊
2020-01-014 - Danielclass task { public: task(int data) : data_(data) {} auto lazy_launch() { return [this, count = get_count()]() mutable { ostringstream oss; oss << "Done work " << data_ << " (No. " << count << ") in thread " << this_thread::get_id() << '\n'; msg_ = oss.str(); calculate(); }; } void calculate() { this_thread::sleep_for(100ms); cout << msg_; } private: int data_; string msg_; }; 输出: Done work 37 (No. 2) in thread 3 Done work 37 (No. 2) in thread 3 按引用捕获,应该是线程1输出之前msg_被线程2覆盖了。
作者回复: 是这样。😊
2022-03-213 - 罗 乾 林编译器遇到lambda 表达式时,产生一个匿名的函数对象,各种捕获相当于按值或者按引用设置给匿名对象的成员字段。 不对的地方,望老师指正。 对function<int(int, int)>这货怎么实现的比较好奇,大多数模板参数都是类型,做的都是是类型推导,这货居然是int(int, int)
作者回复: lambda表达式的理解没啥问题。 int(int, int) 也是一个类型:一个接受两个整数参数、返回一个整数的函数。function 的主要复杂性,应该是需要处理函数、函数指针、函数对象等各种情况。函数对象的大小不确定,因而 function 需要在堆上分配内存。operator() 我记得相当于一个虚函数调用的复杂度。
2020-01-012 - 西雨川久我提一个小问题: 原文:虽然函数名字叫 accumulate——累加——但它的行为是通过第四个参数可修改的。我们把上面的加号 + 改成星号 *,上面的计算就从从 1 加到 5 变成了算 5 的阶乘了。 实际上,还需要把第三个参数改成1,否则结果是0.
作者回复: 嗯嗯,你说得很对。👍
2022-11-17归属地:江苏1 - ReCharge& 加本地变量名标明对其按引用捕获(不能在默认捕获符 & 后出现;因其已自动按引用捕获所有本地变量) 老师这句话有问题么?括号内外感觉描述矛盾 &本地变量名:这种写法不被允许么?
作者回复: 我的意思是,可以写 [&a, &b],也可以写 [=, &a, &b],但不能写 [&, &a, &b]。
2022-06-111 - zhengfan吴老师您好,请教一下: 对于形如[]() mutable {}的lamda表达式 还能够被认为是一个constexpr吗?
作者回复: 有意思的问题。实测下来,C++ 不看形式,而是看实质。按你这个形式,能编译过。但如果这个 lambda 表达式真的会修改自己的存储的数值,则不可以是 constexpr。 见: https://godbolt.org/z/wc5axG 写 auto l = [x = 1]() { return x++; }; constexpr auto l = [x = 1]() mutable { return x++; }; 都不行。 auto l = [x = 1]() mutable { return x++; }; 可以。
2020-06-3021