[C++] lambda表达式

lambda是C++11标准的新特性之一,它实际上是一个匿名函数。再详细一点,它是一个匿名的内联函数。

与任何函数类似,一个lambda具有一个返回类型,一个参数列表和一个函数体。但与函数不同,lambda可能定义在函数内部。一个lambda表达式具有如下形式:

[capture list](parameter list) -> return type { function body }
/*  捕获列表       参数列表          返回值类型       函数体    */

捕获列表是定义在该lambda表达式所在函数中所定义的局部变量的列表,参数列表,返回值类型和函数体则与普通函数一样。

参数列表和返回类型可以忽略,但是捕获列表和函数体必须包含:

/*code block 1*/
/*完整的lambda表达式*/
auto function = [] () -> int {
    return 6;
}; //注意,不要忘记这里的";"!

cout << function() << endl;

/*
输出为:
6
*/

上面的定义,是一个完整的lambda表达式的定义。等号右侧的内容是一个lambda表达式,整条语句是一个赋值操作,所以一定不要忘记最后的“;”。

还可以按照如下方式定义:

/*code block 2*/
/*缺少返回类型*/
auto function1 = [] () {
    return 7;
};

/*缺少参数列表和返回类型*/
auto function2 = [] {
    return 8;
};

cout << function1() << endl;
cout << function2() << endl;

/*
输出为:
7
8
*/

虽然上述两种定义方式不完整,但都是正确的。如果不定义参数列表或参数列表为空,则默认无参;如果捕获列表为空,则说明该表达式不从其外部函数捕获局部成员;如果不声明返回类型,编译器会自动推断返回类型。

接下来看这个例子:

/*code block 3*/
#include <iostream>
#include <algorithm>

using namespace std;

int main() {
	int arr[10] = {3, 4, 1, 9, 6, 5, 2, 8, 0, 7};

	for(int i = 0; i < 10; ++i) {
		cout << arr[i] << " ";
	}
	cout << endl;

	sort(arr, arr + 10);
	for(int i = 0; i < 10; ++i) {
		cout << arr[i] << " ";
	}
	cout << endl;

	sort(arr, arr + 10, [](int a, int b) {
		return a > b;
	});
	for(int i = 0; i < 10; ++i) {
		cout << arr[i] << " ";
	}
	cout << endl;

	return 0;
}

/*
输出为:
3 4 1 9 6 5 2 8 0 7
0 1 2 3 4 5 6 7 8 9
9 8 7 6 5 4 3 2 1 0
*/

代码块3使用了std::sort()对数组进行排序。默认升序,如果想按照降序排列,需要自己实现比较函数。可以通过函数对象或者lambda表达式实现。很明显,lambda表达式的实现更简单。如果这个比较函数只使用一次的话,lambda表达式应该作为首选方法。在代码块中,没有指明返回类型,但是根据判断,返回类型为bool。

捕获列表只用于局部非static变量,lambda可以直接使用局部static变量和它所在函数之外声明的名字。(《C++ Primer 5》)

接下来看看捕获列表的用法吧:

[]不捕获任何变量
[=]捕获所有外部变量,按值捕获
[&]捕获所有外部变量,按引用捕获
[variable]捕获变量variable,按值捕获
[&variable]捕获变量variable,按引用捕获
[this]捕获this指针,该lambda表达式为可以访问该类的所有成员以及成员函数。
[=, &foo]除变量foo按引用捕获外,其余所有变量按值捕获。
[&, foo]除变量foo按值捕获外,其余所有变量按引用捕获。

在按值捕获某(些)变量时,如果要更改捕获的变量,编译器会报错:
error: assignment of read-only variable 'a'

使用较简单,就不一一给出例子。

当定义一个lambda时,编译器生成一个与lambda对应的新的(未命名的)类类型。当向一个函数传递一个lambda时,同时定义了一个新类型和该类型的一个对象;传递的参数就是此编译器生成的类类型的未命名对象。类似的,当使用auto定义一个用lambda初始化的变量时,定义了一个从lambda生活层的类型的对象。(《C++ Primer 5》)

/*code block 4*/

/*用代码块3中的代码举例子*/
sort(arr, arr + 10, [](int a, int b) {
	return a > b;
});

上述行为类似这样的一个类的对象:(类名未知),operator()()的参数列表和lambda表达式的参数列表完全一致。
默认情况下,lambda是不能更改其捕获成员的,所以该成员函数为const的,如果是通过引用捕获,则该成员函数为非const的。
class Unknown {
	bool operator()(int lhs, int rhs) const {
		return lhs > rhs;
	}
};

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值