【C++】 Lambda表达式详解

这篇具有很好参考价值的文章主要介绍了【C++】 Lambda表达式详解。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

🛫 问题

描述

记得去年立了一个重学C++新特性的flag,可是真的太忙了,大部分精力都花在全栈上了,今年开始看一些开源源码,发现各种奇怪的语法,根本看不懂,不学不行了。而且接触了很多语言后,发现新特性的确能提高开发效率,所以还是重新学习下C++吧。

环境

版本号 描述
文章日期 2023-06-09
操作系统 Win11 - 21H2 - 22000.1335
C++在线工具 https://c.runoob.com/compile/12/

1️⃣ 什么是Lambda表达式

Lambda表达式是C++11中新增的一种函数对象,它可以方便地定义一个匿名函数,从而简化代码的编写。
Lambda表达式的本质是一个可调用对象,可以像函数一样被调用,也可以作为函数参数或返回值。

Lambda 表达式的各个部分

下面是作为第三个参数 std::sort() 传递给函数的简单 lambda:

#include <algorithm>
#include <cmath>

void abssort(float* x, unsigned n) {
    std::sort(x, x + n,
        // 下面是一个简单的 `Lambda 表达式`
        [](float a, float b) {
            return (std::abs(a) < std::abs(b));
        } 
    ); 
}

下图显示了 lambda 语法的各个部分:

  1. 捕获列表:(capture list)(在 C++ 规范中也称为 Lambda 引导。)
  2. 参数列表:(parameters list)(可选)。 (也称为 Lambda 声明符)
  3. mutable 规范:(可选)。
  4. 异常说明:exception-specification(可选)。
  5. 返回类型:trailing-return-type(可选)。
  6. Lambda 体:也就是函数体。
    【C++】 Lambda表达式详解

引用大佬的一张图:
【C++】 Lambda表达式详解

2️⃣ 优缺点

优点

  1. 简化代码:Lambda表达式可以将一些冗长的代码简化为一行代码,使代码更加简洁。
  2. 提高可读性:Lambda表达式可以使代码更加易读,减少了一些冗余的代码,使代码更加简洁明了。
  3. 提高可维护性:Lambda表达式可以使代码更加易于维护,因为它可以将一些复杂的逻辑封装在一个方法中,使代码更加模块化。

缺点

  1. 学习成本高:Lambda表达式需要一定的学习成本,需要理解函数式编程的概念和Lambda表达式的语法。
  2. 可读性降低:有时候Lambda表达式可能会使代码变得更加难以理解,特别是当Lambda表达式嵌套时。
  3. 性能问题:Lambda表达式可能会影响程序的性能,因为它需要创建一个新的对象来表示Lambda表达式。但是,这种影响通常是微不足道的,只有在极端情况下才会有明显的性能问题。

3️⃣ 使用场景

Lambda表达式可以用于任何需要函数对象的场景,例如:

  • STL算法中需要传递函数对象的地方,如std::sortstd::for_each等;
  • STL容器中需要传递比较函数的地方,如std::setstd::map等;
  • 多线程编程中需要传递回调函数的地方,如std::threadstd::async等。

在线C++工具

为了方便演示,找了个在线C++工具 https://c.runoob.com/compile/12/ ,可以直接在网页中运行C++代码。
效果图如下:
【C++】 Lambda表达式详解

STL算法库

find_if应用实例

#include <iostream>
#include <deque>
#include <algorithm>

using namespace std;

int main()
{
	int x = 5;
	int y = 10;
	deque<int> coll = { 1, 3, 19, 5, 13, 7, 11, 2, 17 };
	auto pos = find_if(coll.cbegin(), coll.cend(), [=](int i) {                 
		return i > x && i < y;
	});
	
	cout << "find " << (pos != coll.end() ? "success" : "failed");

   return 0;
}

sort实例,用于对一个整数数组进行排序:
以上代码中,Lambda表达式[](int a, int b) { return a < b; }用于指定排序规则,即按照升序排列。

#include <iostream>
#include <algorithm>
#include <vector>

int main()
{
    std::vector<int> vec = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5};

    // 使用Lambda表达式对vec进行排序
    std::sort(vec.begin(), vec.end(), [](int a, int b) { return a < b; });

    // 输出排序后的结果
    // 1 1 2 3 3 4 5 5 5 6 9 
    for (auto x : vec)
    {
        std::cout << x << " ";
    }
    std::cout << std::endl;

    return 0;
}

STL容器中需要传递比较函数

在线工具不能正常运行:

#include <iostream>
#include <thread>
#include <vector>
#include <algorithm>
#include <string>
#include <map>

int LambdaContainer()
{
	auto fc = [](const std::string& a, const std::string& b) {
		return a.length() > b.length();
	};
	std::map<std::string, int, decltype(fc)> myMap = { {"apple", 5}, {"banana0", 10}, {"orange", 15} };

	// 使用迭代器遍历map
	std::cout << "使用迭代器遍历map:" << std::endl;
	for (auto it = myMap.begin(); it != myMap.end(); ++it) {
		std::cout << it->first << " : " << it->second << std::endl;
	}

	// 需要C++20支持
	std::map < std::string, int, decltype([](const std::string& a, const std::string& b) {
		return a.length() < b.length();
	}) > myMap2 = { {"apple", 5}, {"banana0", 10}, {"orange", 15} };
	// 使用范围for循环遍历map
	std::cout << "\n\n使用范围for循环遍历map:" << std::endl;
	for (const auto& [key, value] : myMap2) {
	    std::cout << key << " : " << value << std::endl;
	}

	return 0;
}

针对myMap,需要C++17支持
针对myMap2decltype中使用lambda需要C++20支持
【C++】 Lambda表达式详解

多线程示例

在线工具不能正常运行:
【C++】 Lambda表达式详解

#include <iostream>
#include <thread>
#include <vector>
#include <algorithm>

int main()
{
    // vector 容器存储线程
    std::vector<std::thread> workers;
    for (int i = 0; i < 5; i++) 
    {
        workers.push_back(std::thread([]() 
        {
            std::cout << "thread function\n";
        }));
    }
    std::cout << "main thread\n";

    // 通过 for_each 循环每一个线程
    // 第三个参数赋值一个task任务
    // 符号'[]'会告诉编译器我们正在用一个匿名函数
    // lambda函数将它的参数作为线程的引用t
    // 然后一个一个的join
    std::for_each(workers.begin(), workers.end(), [](std::thread &t) 
    {
        t.join();
    });

    return 0;
}

4️⃣ Lambda表达式与函数指针的比较

Lambda表达式与函数指针类似,都可以用于定义函数对象。但是,Lambda表达式相比函数指针具有以下优点:

  • Lambda表达式可以捕获外部变量,从而方便地访问外部环境;
  • Lambda表达式可以定义在函数内部,从而避免了命名冲突的问题;
  • Lambda表达式可以使用auto关键字自动推导返回值类型,从而简化代码。

5️⃣ 捕获列表

Lambda表达式的捕获列表用于指定Lambda表达式中使用的外部变量。捕获列表可以为空,也可以包含以下内容:

  • []:不捕获任何外部变量;
  • [&]:以引用方式捕获所有外部变量;
  • [=]:以值方式捕获所有外部变量;
  • [var1, var2, ...]:指定捕获特定的外部变量;
  • [&, var1, var2, ...]:以引用方式捕获所有外部变量,并指定捕获特定的外部变量;
  • [=, &var1, &var2, ...]:以值方式捕获所有外部变量,并以引用方式捕获特定的外部变量。

6️⃣ 返回值类型

Lambda表达式的返回值类型可以显式指定,也可以使用auto关键字自动推导。如果Lambda表达式的函数体只有一条语句,且该语句的返回值类型可以自动推导,则可以省略返回值类型和return关键字。

7️⃣ 工作原理

编译器会把一个Lambda表达式生成一个匿名类的匿名对象,并在类中重载函数调用运算符,实现了一个operator()方法。
auto print = []{cout << "Hello World!" << endl; };为例,编译器会把上面这一句翻译为下面的代码:

class print_class
{
public:
	void operator()(void) const
	{
		cout << "Hello World!" << endl;
	}
};
// 用构造的类创建对象,print此时就是一个函数对象
auto print = print_class();

ps: 仿函数(functor)又称为函数对象(function object)是一个能行使函数功能的类。仿函数的语法几乎和我们普通的函数调用一样,不过作为仿函数的类,都必须重载operator()运算符,仿函数与Lamdba表达式的作用是一致的。
stl中含有大量类似的对象,如std::less
【C++】 Lambda表达式详解文章来源地址https://www.toymoban.com/news/detail-477382.html

📖 参考资料

  • 微软Lambda教程 https://learn.microsoft.com/zh-cn/cpp/cpp/lambda-expressions-in-cpp?view=msvc-170
  • C++ Lambda表达式详解 https://blog.csdn.net/qq_37085158/article/details/124626913
  • 在线C++工具 https://c.runoob.com/compile/12/
  • 在线C++工具2 https://www.json.cn/runcode/run_cpp920/

到了这里,关于【C++】 Lambda表达式详解的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • java lambda表达式详解

    我们知道,在Java中,接口是不能实例化的,但是接口对象可以指向它的实现类对象。如果接口连实现对象都没有呢?那还可以使用匿名类的方式,如下: 复制 但是,使用匿名内部的方式,代码量其实并不是非常简洁,而为了使代码更加的简洁,Java引进了 Lambda 表达式的写法,

    2024年02月03日
    浏览(50)
  • C++的lambda表达式(匿名函数)

    从C++11开始,C++也支持使用lambda表达式(匿名函数)。Lambda表达式是一种便捷的方式,可以定义一个函数对象,而无需使用显式的函数对象类型或函数指针语法。 C++中的 lambda表达式的基本语法如下: 其中各个部分的含义如下: capture list :用于指定所捕获的外部变量列表。可

    2024年02月08日
    浏览(46)
  • 【C++】C++11——lambda表达式

    我们之前都是通过函数指针、仿函数的方式可以像函数使用的对象,在C++11之后,就有了Lambda表达式 为了实现一个比较算法, 都要重新去写一个类,如果每次比较的逻辑不一样,还要去实现多个类,特别是相同类的命名,看代码的人就遭殃了,非常的烦,这些都非常地不方便

    2024年01月17日
    浏览(52)
  • C++ Lambda表达式的常见用法

    ⭐️我叫忆_恒心,一名喜欢书写博客的在读研究生👨‍🎓。 如果觉得本文能帮到您, 麻烦点个赞 👍呗! 近期会不断在专栏里进行更新讲解博客~~~ 有什么问题的小伙伴 欢迎留言提问欧,喜欢的小伙伴给个三连支持一下呗。👍⭐️❤️ 作为C++11的新特性的Lambada表达式本身

    2024年01月16日
    浏览(71)
  • Java 8 Lambda表达式详解

    在Java 8中,引入了一种全新的函数编程概念,即Lambda表达式。这是一个重要的进步,它让Java的功能得以大幅扩展,同时还让代码变得更加简洁明了。接下来,我将详细介绍Lambda表达式的相关知识,包括其基本语法、使用场景和特性。 Lambda表达式基本的语法可以分为三个部分

    2024年02月08日
    浏览(84)
  • 【C++】C++11语法 ~ lambda 表达式

    (꒪ꇴ꒪(꒪ꇴ꒪ )🐣,我是 Scort 目前状态:大三非科班啃C++中 🌍博客主页:张小姐的猫~江湖背景 快上车🚘,握好方向盘跟我有一起打天下嘞! 送给自己的一句鸡汤🤔: 🔥真正的大师永远怀着一颗学徒的心 作者水平很有限,如果发现错误,可在评论区指正,感谢🙏 🎉🎉

    2024年01月20日
    浏览(62)
  • C++系列十:日常学习-Lambda表达式

    目录 前言 必备理论知识: 例子: 20230920 加 例如 对函数指针和指针函数补充: 有C#经验,使用起来,驾轻就熟。 就是语法糖。但是也要熟悉用法,才好众享丝滑。 内容参考: Chatjpt、文心一言 C++ lambda 表达式是一种功能强大的编程工具,它允许您在代码中创建匿名函数或闭

    2024年02月08日
    浏览(54)
  • 【Java基础】Java Lambda表达式详解

    Lambda 表达式,即函数式编程是 JDK8 的一个新特性,也被称为闭包,Lambda表达式允许把函数作为一个方法的参数,即行为参数化,函数作为参数传递进方法中。 Lambda表达式可以取代大部分的匿名内部类,写出更优雅的 Java 代码,尤其在集合的遍历和其他集合操作中,可以极大

    2024年02月04日
    浏览(55)
  • Java中Lambda表达式使用及详解

    Lambda表达式(闭包):java8的新特性,lambda运行将函数作为一个方法的参数,也就是函数作为参数传递到方法中。使用lambda表达式可以让代码更加简洁。 Lambda表达式的使用场景:用以简化接口实现。 关于接口实现,可以有很多种方式来实现。例如:设计接口的实现类、使用匿

    2024年02月03日
    浏览(59)
  • C++ lambda表达式函数递归调用简单写法实现

    在C++11中,lambda表达式函数递归往往会带上 functional 头文件。书写形式如下: 还有相对简单点的第二种写法(C++14): 对于第二种, auto fib 的作用是为了在 lambda 表达式内部能够递归调用自身。在 C++14 中,lambda 表达式默认是无法直接递归调用的,因为在 lambda 内部无法访问到

    2024年02月15日
    浏览(50)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包