• 【C++】超详细入门——lambda表达式



    1、可调用对象

    如果一个对象或表达式可以使用调用运算符(()),则可以称它为可调用对象。

    可调用对象共有四种:

    • 函数
    • 函数指针
    • 重载了函数调用运算符的类
    • lambda表达式

    可调用对象用途很广,包括在调用泛型算法函数(sort(),find_if()等)时,可以传入可调用对象,来指明泛型算法要对指定范围内的元素进行哪种操作。


    2、谓词

    再来看一下谓词的概念。

    谓词是一个可调用的表达式,其返回结果是一个能用作条件的值。标准库算法所使用的的谓词分两类:

    • 一元谓词:只接受单一参数。
    • 二元谓词:接受两个参数。

    一般来说,可调用对象在泛型算法中都被用作谓词传入函数。可以说谓词是可调用对象的一种,也可以说可调用对象可以当做谓词。


    3、尾置返回类型

    介绍lambda表达式之前,最后再引入一个概念:尾置返回类型。

    C++11 中尾置返回类型用来简化函数声明,以一个跟在形参列表后面的 -> 开头,函数名前需要用 auto 来表明该函数的返回类型是用尾置返回类型表示的。

    尾置返回类型尤其对于返回类型比较复杂的函数最有效,比如数组的指针或数组的引用:

    //返回整型数组指针的函数,形参为一个int。
    int (*func(int i))[10];
    //使用类型别名
    auto func(int i) -> int (*)[10];
    
    • 1
    • 2
    • 3
    • 4

    这样看来使用类型别名声明复杂函数就更简洁明了吧。


    4、lambda表达式

    终于到它了——lambda表达式。

    lambda表达式又称匿名函数,可以把他理解为未命名的内联函数。它必须使用尾置返回类型来定义,其定义形式为:

    [capture list] (parameter list) -> return type {function body}
    
    • 1

    各部分解释:
    capture list:是 lambda 所在函数中定义的局部变量的列表(一般不用);
    return type:返回类型;
    parameter list:参数列表;
    function body:函数体。

    4.1无参lambda表达式

    lambda表达式中可以忽略参数列表和返回类型,忽略参数列表相当于空参数列表,忽略返回类型可以从 return 语句中推断出返回类型:

    例子:

    auto f = [] {return 0;};
    auto f = [] () -> int {return 0;};  //等价定义
    cout << f() << endl;
    
    • 1
    • 2
    • 3

    这里定义了一个可调用对象 f,不接受参数,返回 0。

    4.2有参lambda表达式

    与普通函数一样 lambda 的形参使用实参初始化。实参和形参的类型必须匹配,而且不能有默认参数。

    例一:

    bool is_shorter(const string &s1, const string &s2){
        return s1.size()<s2.size();
    }
    sort(words.begin(), words.end(), is_shorter);
    sort(words.begin(), words.end(), [](const string &a, const string &b)
    	{return a.size() < b.size();});//等价定义
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    接受二元谓词的 sort 用传入的谓词替代 < 操作。

    第一个 sort 中把 is_shorter 函数作为二元谓词传入,将 vector 按照字符串长度排序。
    第二个把 lambda 表达式作为二元谓词传入,与上一个等价。

    例二:

    bool is_large(const string &s, string::size_type sz){
        return s.size() > sz;
    }
    auto iter = find_if(words.begin(), words.end(), is_large);
    auto iter = find_if(words.begin(), words.end(), 
    	[](const string &s, string::size_type sz){return s.size() > sz;})
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    这段代码看似是返回 vector 中指向第一个长度大于 sz 的元素的迭代器,但是编译起来却会报错,这是因为 find_if 接受的参数是一元谓词,这里的 is_large 却是二元谓词。

    别着急,利用capture list可以解决传入多个参数的问题。

    4.3使用capture list

    当 lambda 表达式出现在函数中,就可以使用函数中的局部变量,我们需要通过 capture list 指出将会使用的变量。

    这样我们就可以直接使用局部变量 sz,而不用通过传参使用它了:

    string::size_type sz = 5;
    auto iter = find_if(words.begin(), words.end(), 
    	[sz](const string &s, string::size_type sz){return s.size() > sz;})
    
    • 1
    • 2
    • 3

    🎉到此 lambda 表达式的讲解就结束了,从今天开始更新 C++ 的基础知识,后面应该会讲解一下标准容器,并手动实现。
    希望大家多多关注,三连支持。你们的支持是我源源不断创作的动力。

  • 相关阅读:
    OpenGL 图像绿幕抠图
    数据结构与算法之美 复杂度分析(上)
    基于JAVA的新闻发布管理系统开发参考【数据库设计、源码、开题报告】
    初识树(c语言)
    【译】ASP.NET Core 6 中的性能改进
    openGauss学习笔记-101 openGauss 数据库管理-管理数据库安全-客户端接入之用SSH隧道进行安全的TCP/IP连接
    HarmonyOS开发之一——环境安装和HelloWorld
    Linux学习笔记:什么是文件描述符
    卷积神经网络的常用改进
    Android SurfaceFlinger导读(01) surfaceFlinger谁写的?他还干了什么?
  • 原文地址:https://blog.csdn.net/weixin_45773137/article/details/126225061