C++11(4)

万众瞩目的C++11特辑来了,本章将继续讲解C++11更新的内容,不过C++11的内容也快接近尾声了。

目录

10。lambda表达式

11。lambda捕捉列表[]

捕捉列表说明

lambda捕捉列表实际应用


10。lambda表达式

#include<iostream>
using namespace std;
#include<algorithm>
#include<vector>
struct Goods
{
    string _name; // 名字
    double _price; // 价格
    int _evaluate; // 评价
    //...

    Goods(const char* str, double price, int evaluate)
        :_name(str)
        , _price(price)
        , _evaluate(evaluate)
    {}
};

int main()
{
    //lambda表达式
    // lambda 匿名函数的对象, 所以肯定有类型,所以肯定有返回值
    //即返回一个lambda类型的对象

    auto ret = [](int x, int y)->int {return x + y; };
    //为什么用auto自动推导呢,因为lambda的类型lambda_uuid过于复杂了,详情请看汇编
    //这个切记lambda的返回值不是返回函数体里面运算得出了类型,虽然return了
    cout << ret(1, 1) << endl;
    cout << ret(3, 1) << endl;
    //上面展示的是lambda表达式的完整形式
    //最前面的捕捉列表,没有捕捉对象可以没有任何东西,但是[]必须写上
    //后面的参数部分,确实不需要传参可以不写,明确函数体返回值的可以不写->返回值
    //函数体部分不可以省略
    //所以只有[]和函数体是必须写上的

    // 返回值类型可自动推导类型,所以可以省略
    // 无参数可以省略

    auto it = []
        {
            cout << "wfwfwq" << endl;
            cout << "wfwfwq" << endl;
            cout << "wfwfwq" << endl;
            cout << "wfwfwq" << endl;
            //return 0;//有没有return都无所谓的,只要返回值确定或者无返回值
        };
    it();//外部调用方法
    return 0;
}

//通过观察底层汇编可以发现lambda和仿函数的实现有点像,
//所以这两个是可以互相替代使用的

然而我们会发现,在之前使用的库里面的sort函数就使用了仿函数,所以我们可以使用lambda表达式对其进行改造。
struct comp1//比较价格的升序
{
    bool operator()(const Goods& gl, const Goods& gr)
    {
        return gl._price < gr._price;
    }
};

struct comp2//比较价格的降序
{
    bool operator()(const Goods& gl, const Goods& gr)
    {
        return gl._price > gr._price;
    }
};
int main()
{
    vector<Goods> v = { { "苹果", 2.1, 5 }, { "香蕉", 3, 4 }, { "橙子", 2.2, 3 }, { "菠萝", 1.5, 4 } };
    sort(v.begin(), v.end(), comp1());
    sort(v.begin(), v.end(), [](const Goods& gl, const Goods& gr) 
        {
            return gl._price > gr._price;
        });
    return 0;
}

以下为调试结果:

//使用lambda表达式的优点是便于使用者马上就可以看出在进行什么操作,升序排列降序排列什么的
//比较直观
//其实也不需要去看底层这个comp1作为一个类,comp1()就是匿名函数对象,那和lambda的本质不是一样了吗

11。lambda捕捉列表[]

//接着聊一下捕捉列表是个什么东西,有什么作用

//捕捉列表的本质就是在初始化函数的参数!!!
int main()
{
    int a = 2;
    int b = 5;
    auto swap1 = [](int& x, int& y)
        {
            //只能用当前lambda局部域和捕捉的对象
            int temp = x;
            x = y;
            y = temp;
        };
    swap1(a, b);
    cout << a << endl;
    cout << b << endl;
    int c = 6;
    int d = 7;
    //发现swap1将两个值交换了
    auto swap2 = [c, d]()mutable
        {
            // 只能用当前lambda局部域和捕捉的对象
            int temp = c;
            c = d;
            d = temp;
            //上面报错的信息为必须是可修改的左值
            //说明传值捕捉指定参数个体本质是一种拷贝,并且const修饰了
            //解决办法在[]后面加上()mutable,mutable的作用是去除const属性

        };
    swap2();//传值捕捉还是需要调用的,只是参数固定了,不需要写了(不要忘了调用)
    cout << c << endl;
    cout << d << endl;
    //发现没有交换成功, 结合上面swap1交换成功的例子可以看出传值捕捉
    //修改了不会影响外面被捕捉的值,因为是一种拷贝,如果执意要改需要传引用捕捉
    //这里侧面体现了mutable和传值捕捉都没有什么实际价值

    auto swap3 = [&c, &d]//这里不是取地址是引用
        {
            int tmp = c;
            c = d;
            d = tmp;
        };
    swap3();
    cout << c << endl;
    cout << d << endl;

    return 0;
}

// 只能用当前lambda局部域和捕捉的对象和全局对象

捕捉列表说明

int main()
{
    //还有其他的捕捉方式
    int a = 0;
    int b = 1, c = 1;
    int d = 2;
    // 所有值传值捕捉
    auto func1 = [=]
        {
            int ret = a + b + c + d;
            return ret;//如果要取到ret的值就需要返回,因为出了func1函数的局部域就销毁了
        };
    // 所有值传引用捕捉
    auto func2 = [&]
        {
            a++;
            b++;
            c++;
            d++;
            int ret = a + b + c + d;
            return ret;//如果要取到ret的值就需要返回,因为出了func1函数的局部域就销毁了
        };
    // 混合捕捉
    auto func3 = [&a, b]
        {
            a++;
            //b++;//无法修改
            int ret = a + b;
            return ret;//如果要取到ret的值就需要返回,因为出了func1函数的局部域就销毁了
        };
    // 混合捕捉
    // 除d以外所有值以引用方式捕捉,d用传值捕捉

    auto func4 = [&, d]
        {
            a++;
            b++;
            c++;
            //d++;
            int ret = a + b + c + d;
            return ret;//如果要取到ret的值就需要返回,因为出了func1函数的局部域就销毁了
        };
    // 除d以外所有值以传值方式捕捉,d用传引用捕捉
    auto func5 = [=, &d]() mutable
            {
                a++;
                b++;
                c++;
                d++;
                int ret = a + b + c + d;
            };
    int p1 = func1();
    int p2 = func2();
    int p3 = func3();
    int p4 = func4();
    cout << p1 << endl;
    return 0;
    //太多组合方式了

}

lambda捕捉列表实际应用

下面的例子是一个计算利息的程序(后面会不断的使用这个例子)

class Rate
{
public:
    Rate(double rate) 
        : _rate(rate)
//一般是放在下面
    {}

    double operator()(double money, int year)
    {
        return money * _rate * year;
//计算当年的利息
    }
private:
    double _rate;
};

int main()
{
  
 // 函数对象
    double rate = 0.015;
    Rate r1(rate);
    cout << r1(10000, 2) << endl;

    // lambda[]捕捉在全局域捕捉
    auto r2 = [rate](double monty, int year)->double
    {
        return monty * rate * year;
    };

    cout << r2(10000, 2) << endl;

    int x = 1, y = 2;
  
 //执行之后发现捕捉列表也不是什么都捕捉的,对函数体里面有用的变量才捕捉
    auto r3 = [=](double monty, int year)->double
    {
        return monty * rate * year;
    };

    cout << r3(10000, 2) << endl;


    return 0;
}

现在解决一下关于lambda对象的类型的问题:请看下图

可以看到图片//lambda那里有一个call   <lambda_什么什么>很长的一串字符,这个就是lambda对象的类型,这个可以看成是一个类(因为有类操作符::),类就是类型,由于太长了就简称lambda_uuid,所有lambda是有类型的并且可以取到的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值