C++11关于Lambda表达式详细介绍

一、Lambda表达式

1.Lambda表达式的定义

Lambda表达式是C++11提供的一个新语法,使用起来非常方便。

在C++11之前,如果我们要使用sort函数进行排序,默认是排升序,如果我们想要排降序,就需要传递进一个库里面写好的仿函数。

#include <algorithm>
#include <functional>

int main()
{
	int array[] = {4,1,8,5,3,7,0,9,2,6};
	// 默认按照小于比较,排出来结果是升序
	std::sort(array, array+sizeof(array)/sizeof(array[0]));
	// 如果需要降序,需要改变元素的比较规则
	std::sort(array, array + sizeof(array) / sizeof(array[0]), greater<int>());
	return 0;
}

对于内置类型的排序,这种方法不算特别麻烦。但实际上我们使用的排序都不会是单一元素的排序,一般排序都是多种元素结合的排序,这就需要我们对自定义类型进行排序。比如结构体,我们要控制结构体内不同类型数据的比较规则,就需要自己写一个仿函数来控制排序。

比如我们要写一个学生信息的排序,按照身高高的学生优先,如果身高相同则年龄小的学生优先这样的规则进行排序。

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

using namespace std;

struct Student
{
    string _name; // 学生名字
    int _age;     // 学生年龄
    int _height;  // 学生身高

    Student(const string &name, const int &age, const int &height)
        : _name(name), _age(age), _height(height)
    {
    }
};

// 按照身高高的优先,如果身高相同则按年龄小的优先
struct CmpStudent
{
    bool operator()(const Student& s1, const Student& s2)
    {
        if(s1._height == s2._height)
        {
            return s1._age < s2._age;
        }
        else
        {
            return s1._height > s2._height;
        }
    }
};

int main()
{
    vector<Student> v = {{"张三", 18, 180}, {"李四", 15, 200}, {"王五", 13, 200}};
    sort(v.begin(), v.end(), CmpStudent());
    for(auto e : v)
    {
        cout << e._name << " - " << e._age << " - " << e._height << endl;
    }
    return 0;
}

上面实现排序的做法相对比较麻烦,我们可以采用Lambda表达式来简化它。

Lambda表达式其实是一种全新的定义函数的方法,它可以匿名定义一个函数

例如上面的例子,我们可以利用Lambda表达式来简化:

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

using namespace std;

struct Student
{
    string _name; // 学生名字
    int _age;     // 学生年龄
    int _height;  // 学生身高

    Student(const string &name, const int &age, const int &height)
        : _name(name), _age(age), _height(height)
    {
    }
};


int main()
{
    vector<Student> v = {{"张三", 18, 180}, {"李四", 15, 200}, {"王五", 13, 200}};
    // Lambda表达式
    sort(v.begin(), v.end(), [](const Student& s1, const Student& s2){
        if(s1._height == s2._height)
        {
            return s1._age < s2._age;
        }
        else
        {
            return s1._height > s2._height;
        }
    });
    for(auto e : v)
    {
        cout << e._name << " - " << e._age << " - " << e._height << endl;
    }
    return 0;
}

2.Lambda表达式书写格式

// Lambda表达式书写格式
[capture-list](parameters)mutable -> returntype{statement}
  • [capture-list]:这是捕捉列表,该列表总是出现在Lambda表达式的开始位置,编译器根据[]来判断接下来的代码是否为Lambda表达式,捕捉列表可以捕捉上下文中的变量供Lambda表达式使用。
  • (parameters):这是参数列表,与普通函数的参数列表类似。如果这个函数不需要传递参数,可以连同()一起省略。
  • mutable:默认情况下,Lambda函数总是一个const函数,mutable可以取消其常量性。如果使用了该修饰符修饰,参数列表不可以省略(即使参数为空也不可以省略)。
  • ->returntype:函数的返回值类型,如果函数没有返回值类型(即void),可以省略;如果函数的返回值类型明确,也可以省略,由编译器对返回类型进行推导。
  • {statement}:函数体,在函数体内除了可以使用参数列表的参数以外,还可以使用捕捉列表捕捉到的变量。
// 所以这是最简单的Lambda表达式,该Lambda表达式没有任何意义
[]{};

例如我们可以使用Lambda表达式写一个两数相加的Add函数:

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

using namespace std;

int main()
{
    int a = 10, b = 100;
    auto Add = [](int x, int y)->int{
        return x + y;
    };
    cout << Add(a, b) << endl;
    return 0;
}

3.捕捉列表的规则

捕捉列表描述了上下文数据中哪些数据可以被Lambda表达式使用,它的使用非常灵活。

传值方式捕捉变量:

int main()
{
    int a = 10, b = 20;
    // 传值捕捉
    auto Func1 = [a, b]{
        return a + b;
    };
    cout << Func1() << endl;
    return 0;
}

传引用方式捕捉变量:

int main()
{
    int a = 10, b = 20;
    // 传引用捕捉
    auto Func2 = [&a, &b]{
        int tmp = a;
        a = b;
        b = tmp;
    };
    Func2();
    cout << a << " - " << b << endl;
    return 0;
}

传值方式捕捉父作用域中的所有变量(包括this):
(父作用域指Lambda表达式语句所在的作用域)

int main()
{
    int a = 10, b = 20, c = 1, d = 2, e = 3;
    // 传值方式捕捉父作用域中的所有变量(包括this)
    auto Func3 = [=]{
        return a + b + c + d + e;
    };
    cout << Func3() << endl;
    return 0;
}

传引用方式捕捉父作用域中的所有变量(包括this):

int main()
{
    int a = 10, b = 20, c = 1, d = 2, e = 3;
    // 传引用方式捕捉父作用域中的所有变量(包括this)
    auto Func4 = [&]{
        a = a + b + c + d + e;
    };
    Func3();
    cout << a << endl;
    return 0;
}

混合捕捉:

int main()
{
    int a = 10, b = 20, ret = 0;
    // 混合方式
    auto Func5 = [a, b, &ret]{
        ret = a + b;
    };
    Func5();
    cout << ret << endl;

    // ret传引用捕捉,其它全部传值捕捉
    auto Func6 = [=, &ret]{
        ret = a + b;
    };
    Func6();
    cout << ret << endl;
    return 0;
}

二、Lambda表达式的底层原理

仿函数就是一个函数对象,是一个可以像函数一样使用的对象,它的类里重载了operator()运算符。

// 函数对象
class AddUtil
{
public:
    AddUtil(int a = 0, int b = 0)
        : _a(a), _b(b)
    {
    }

    int operator()()
    {
        return _a + _b; 
    }

private:
    int _a;
    int _b;
};

int main()
{
    AddUtil A(10, 20);
    cout << A() << endl;
    return 0;
}

Lambda表达式实际在底层实现的时候,编译器是完全按照函数对象的方式来处理的,如果我们定义了一个Lambda表达式,编译器会自动生成一个类,在该类中重载operator()。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值