Lambda表达式,有用的小帮手

427 阅读3分钟

这是我参与8月更文挑战的第3天,活动详情查看:8月更文挑战

不知道大家在写代码时有没有遇到过这种情况:有时需要用到一个内容非常少的一个函数,比如在调用排序算法时std::sort,先暂停下,在这里先简单讨论下sort

std::sort是C++标准库算法文件里的一个排序算法(快速排序(不完全是)),复杂度为O(N·log(N))(不一定是这个,可能还会恶化到n^2),扯远了,下面说下sort的几个参数,sort其中一个函数重载如下:

void sort (RandomAccessIterator first, RandomAccessIterator last, Compare comp);

其中first与last可以理解为容器要排序的范围,即起始位置以及结束位置;而comp为一个比较函数或者仿函数的名字,sort了解到这即可;

如果我们就为一个参数去定义一个函数或者定义一个仿函数,那也太麻烦了,于是lambda在这里就体现了优点;具体好在哪里呢?看如下代码:

std::vector<int> c={1,2,3,4,5,6,7,8,9};
bool compare(int a,int b){//这里只是简单写下,还可能更复杂
    return a>b;
}
sort(c.begin(),c.end(),compare);
std::vector<int> c={1,2,3,4,5,6,7,8,9};
sort(c.begin(),c.end(),[](int a,int b){return a>b;}); 

两段代码一对比是不是精简了好多,而且更清晰,更明了,更简洁。

好了好了,该说说Lambda了

Lambda

Lambda的具体格式如下:

auto name =[capture list](parameter list) > return type { function body }(auto\ name\ =)[capture \ list](parameter\ list)\ ->\ return\ type\ \{\ function\ body\ \}

各个参数表达意思如下:

1、capture list表示捕获列表,就是捕获什么外部变量,捕获方式是什么,下文看例子一点就通。

2、parameter list参数列表,和函数一样,可有可无。

3、return type返回类型,可有可无。

4、function body函数体

示例:

auto f1 = [](int a) -> int { return a + 1; };
auto f2 = []() { return 2; };
cout << f1(1) << " " << f2() << endl;

捕获列表具体说明:

格式说明
[]不捕捉任何变量
[&]捕获外部作用域中所有变量,并作为引用在函数体内使用 (按引用捕获)
[=]捕获外部作用域所有变量,在函数内内有个副本使用,拷贝的副本在匿名函数体内部是只读的
[=,&x]按值捕获外部作用域中所有变量,并按照引用捕获外部变量x
[x]按值捕获 x变量,同时不捕获其他变量
[&x]按引用捕获 x变量,同时不捕获其他变量
[this]捕获当前类中的 this 指针,让 lambda 表达式拥有和当前类成员函数同样的访问权限,如果已经使用了 & 或者 =, 默认添加此选项

注意:

1、可以忽略参数列表和返回类型,但必须包含捕获列表和函数体,示例:auto f = [] { return 2; };

2、使用值拷贝的方式捕获外部变量,可读不能写,示例: int a=8888;auto f = [=] {return a++; };

3、如果不指定 lambda 表达式的返回值,编译器会根据 return 语句自动推导返回值的类型,但需要注意的是 labmda表达式不能通过列表初始化自动推导出返回值类型,示例auto f = [] {return {1,3}}; };

4、可以使用std::function和std::bind来存储和操作lambda表达式。

对于注意的第二点,因为在C++2.0中lambda表达式会被看成一个仿函数,即operator()重载(),按照C++标准,operator()的默认属性是const的,一个const成员函数是无法修改成员变量值的,可以采用mutable 取消 operator () 的 const 属性。示例如下:

int a=8888;auto f = [=] ()mutable {return a=a+1; };

对于注意的第四点,示例如下:

#include <iostream>
#include <functional>
int main(void)
{
    // 包装可调用函数
    std::function<int(int)> f1 = [](int a) {return a; };
    // 绑定可调用函数
    std::function<int(int)> f2 = bind([](int a) {return a; }, placeholders::_1);//placeholders::_1绑定的参数/占位符

    // 函数调用
    std::cout << f1(100) << std::endl;
    std::cout << f2(200) << std::endl;
    return 0;
}

好啦,今天文章就到这里了,相信大家会收获满满;