lambda表达式for_each,find_if简介

#include <iostream>
#include <functional>
#include <algorithm>
using namespace std;

class CT {
public:
    int m_i = 5;
    void myfuncpt(int x, int y) {
        auto mylambda1 = [this, &x, y]() { // 无论是
        x = 5;
        y;
        //auto mylambda1 = [=]() {
            return m_i; // 因为有了this,这个访问合法的,用& = 也行
        };
        cout << "myfuncpt::x= " << x << endl;
        cout << mylambda1() << endl;
    }
};

int main() {
    // 一:用法简介
    // c++11:也是一种可调用对象
    // lambda表达式,它定义了一个匿名函数,并且可以捕获一定范围的变量
    auto f = [](int a)->int {
        return a+1;
    };
    cout << f(1) << endl;
    // 特点
    // a)是个匿名函数,也可以理解为“可调用的代码但愿”,或者理解成未命名的内联函数
    // b)它也有一个返回类型,一个参数列表,一个函数体
    // c)与函数不同的是,lambda表达式可以在函数内部定义,这个是常规函数做不到的
    // 格式:
    // [捕捉列表](参数列表)->返回类型{函数体};
    // 这是一个返回类型后置这种语法(lambda表达式的返回类型后置是必须的,这个语法就这么规定);
    // 因为很多时候lambda表达式返回值特别明显,所以允许lambda表达式返回类型省略,编译器可以自动推导;
    // lambda参数可以有默认值
    // 大家要注意,编译器并不是总能推断出返回值类型,如果编译器推断不出来的时候,它会报错,这个时候你就要显示给出返回值类型
    // b)没有参数的时候,参数列表可以省略,甚至()也能省略,所以如下这些格式都合法
    auto f1 = []() {return 1;};
    auto f2 = [] {return 1;};
    cout << f1() << endl;
    cout << f2() << endl;
    //c)捕获列表[]和函数体不能省,必须时刻包含
    //d)lambda调用方法和普通函数相同,都是使用()这种函数调用运算符
    //e)lambda表达式可以不返回任何类型,不返回任何类型就是void
    auto f3 = [] {};
    //f)函数体末尾分号不能省略;
    //二:捕获列表:[捕捉列表]:通过捕获列表来捕获一定范围内的变量,范围是啥意思呢
    //a)[]不捕获任何变量,但不包含静态局部变量。lambda可以直接使用局部静态变量(局部静态变量是不需要捕获的)
    //int s = 9;
    static int s = 9;
    auto f4 = [] {
        return s; //报错(无法捕获外部变量)不认识这个i在哪里定义,看来lambda表达式毕竟是一个匿名函数,按照
    };
    //b)[&]捕获外部作用域中所有变量,并作为引用在函数体内使用
    int i = 9 ;
    auto f5 = [&] {
        i = 5; // 因为&的存在,那么就允许给i赋值,从而就改变了i的值
        return i;
    };
    cout << f5() << endl;
    cout << i << endl;
    //c)[=]:捕获外部作用域中所有的变量,并作为副本(按值)在函数中使用。也就是可以用它的值,但不允许给它赋值
    int o = 9 ;
    auto f6 = [=] {
        return o;
    };
    //d)this:一般用于类中,捕获当前类中this指针,让lambda表达式和当前类成员函数同样的访问权限
    //如果[]中已经使用了&或者=,那么默认已经使用this,说白了,捕获this的目的就是为了在lambda中使用当前
    //类中的成员函数和成员变量
    CT ct;
    int x = 3;
    int y = 4;
    ct.myfuncpt(x, y);
    cout << "x= " << x << " y=" << y << endl;
    //e)[变量名]:如果是多个变量名,则彼此之间用,分割。[变量名]表示按值捕获变量名代表的变量,同时不捕获其他变量
    // [&变量名]:按引用捕获变量名代表的变量,同时不捕获其他变量
    //f)[=, &变量名]:
    //值捕获所有外部变量,但是按引用捕获&中所指的变量.这里这个=必须写在开头位置,开头这个位置表示默认捕获方式
    //也就是说,这个捕获列表,第一个位置是默认的捕获方式(隐式捕获方式)
    //g)[&,变量名]
    //按引用捕获外部的变量,但是按值捕获变量名中所代表的变量,这里这个&必须必须写在开头位置
    //总结:lambda表达式对于能访问的外部变量控制的非常细致
    //三.lambda表达式延迟调用易出错细节分析
    x = 5;
    auto f7 = [=] { // 当遇到auto这一行,也就是在捕获的这个时刻,x的值就已经被赋值到了这个f中了
    //auto f7 = [&] {
        return x;
    };
    x = 10;
    cout << f7() << endl; // 5
    // 也就是说,凡是按值捕获的外部变量,在lambda表达式定义的时候,所有的这些变量就复制了一份
    // 四lambda表达式中的mutalbe(易变的)
    x = 5;
    auto f8 = [=]()mutable { // 注意要加mutable,则()参数列表之外的这个圆括号不能省略
        x = 10;
        return x;
    };
    //五.lambda表达式的类型及存储
    //c++11中lambda表达式的类型被称呼为“闭包类型(Closure Type)“
    //闭包:函数中的函数(可调用对象).本质上是lambda表达式创建的运行时期对象
    //lambda表达式是一种特殊的,匿名的,类类型(闭包类)的对象,(也就是定义一个类类型,又
    //生成一个匿名该类类型的对象(闭包))
    //我们可以认为它是一个带有operator()的类类型对象,也就是仿函数(函数对象)
    //所以,我们可以用std::function和std::bind来保存和调用lambda表达式,每个lambda都会
    //触发编译给咱们生成一个独一的类类型
    //lambda表达式语法,是我们可以就地定义匿名函数(就地封装短小功能的闭包)
    //auto f1 = [](){}; f1是个未命名的类类型对象
    std::function<int(int)>  fc1 = [](int tv)->int { return tv; };
    cout << fc1(15) << endl;
    std::function<int(int)> fc2 = std::bind( // bind第一个参数是函数指针,第二个函数开始就是真正的函数参数
        [=](int tv) {
            return tv;
        },
        16
    );
    cout << fc2(15) << endl;
    //不捕获任何变量的lambda表达式,也就是捕获列表为空,可以转成一个普通的函数指针
    using functype = int(*) (int);
    functype fp = [](int tv) {return tv;};
    fp(17);
    //(5.1)语法糖概念
    //语法糖:一种便捷写法的意思
    int a[5];
    a[0] = 1; // 便捷写法(语法糖)
    *(a+1) = 3;
    // 语法糖这个词,让我们写的代码更简单,看起来也更容易理解,有效的减少代码出错的机率
    // 语法糖是基于语言的现有特性,构建出一个东西,程序员用起来很方便,但他没有增加语言的原有功能
    // 所以这个lambda表达式,大家也可以看成是仿函数闭包(函数中的函数)的语法糖
    // 六lambda表达式再演示和优点总结
    // (6.1)for_each简介:是个函数模板
    vector<int> myvector = {10, 20, 30, 40, 50};
    for_each(myvector.begin(), myvector.end(), [](int i) {
        cout << i << " ";
    });
    cout << endl;
    int isum = 0;
    for_each(myvector.begin(), myvector.end(), [&isum](int i) {
        isum += i;
        cout << isum << " ";
    });
    cout << endl;
    // (6.2)find_if简介:函数模板find_if
    auto result = find_if(myvector.begin(), myvector.end(), [](int i) {
        cout << i << endl;
        return false; // 只要我返回false,那么find_if就不停的遍历myvector,一直到返回true或者遍历完为止
    });
    //如果find_if第三个参数这个可调用对象(lambda)返回true,find_if就停止遍历
    result = find_if(myvector.begin(), myvector.end(), [](int i) {
        cout << i << endl;
        if(i > 15) {
            return true;
        } else {
            return false; // 只要我返回false,那么find_if就不停的遍历myvector,一直到返回true或者遍历完为止
        }
    });
    // find_if的调用返回一个迭代器,指向第一个满足条件的元素,如果这样的元素不存在,则这个迭代器会指向
    // myvector.end()
    if(result == myvector.end()) {
        cout << "没找到" << endl;
    } else {
        cout << "找到了:" << *result  << endl;
    }
    // 总结:善用lambda表达式,让代码更简洁,更灵活,更强大,提高开发效率,提高可维护性等等.
    return 0;
}

另两篇关于lambda:

https://blog.csdn.net/INGNIGHT/article/details/77680317

https://blog.csdn.net/INGNIGHT/article/details/108294833

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值