0、简介
- 就地匿名定义目标函数或者对象,不需要额外声明函数或者对象;
- 可把函数当作参数给别的函数调用;
- 简洁、高效;
c
vector<int> v{1, 2, 3};
auto f = [](int a, int b) {
return a > b;
};
sort(v.begin(), v.end(), f);
for (auto i : v) {
cout << i << " ";
}
一、基本用法
lambda表达式定义了一个匿名函数,并且可以捕获
一定范围内的变量
c
/**
capture:捕获列表
paramater:参数列表
option:函数选项
returnType:返回值
body:函数体
*/
[capture](paramater) option -> returnType {body};
捕获列表[]
: 捕获一定范围内的变量
参数列表()
:和普通函数的参数列表一样,如果没有参数列表可以省略
c[] () { // 没有参数, 参数列表为空 return 1; } [] { // 没有参数, 参数列表省略不写 return 1; }
option选项
:可以省略
mutable
:可以修改按值传递进来的拷贝(修改的是副本)exception
:指定函数抛出的异常(throw(int, string...)
)返回值类型:
C++ 11
中,lambda
表达式的返回值是通过返回值后置语法
来定义的。(编译器可以自动推导出返回值是什么类型的)函数体:函数的实现,不可省略,可以为空。
二、捕获列表
-
[]
- 不捕捉任何变量 -
[&]
- 捕获外部作用域中所有变量,并作为引用在函数体内部使用(引用传递
) -
[=]
- 捕获外部作用域中所有变量,并作为副本在函数体内使用(按值捕获
)- 拷贝的副本在匿名函数体内部是只读的
-
[=, &val]
-按值
捕获外部作用域中所有变量
,并按照引用捕获外部变量val
-
[val]
- 按值捕获val
变量,同时不捕获其他变量 -
[&val]
- 引用捕获val
变量,同时不捕获其他变量 -
[this]
- 捕获当前类中的this
指针-
让
lambda
表达式拥有和当前类成员函数
同样的访问权限 -
如果已经使用了
&
或者=
,默认添加此选项
-
2.1 示例:类成员方法中
c
class Test {
public:
void output(int x, int y){
// [] () { // 没有捕获外部变量,不能使用类成员 number
// return number; // [Error] 'this' was not captured for this lambda function
// };
[=] () { // 值拷贝方式捕获
return number + x + y; // OK
};
[&] () { // 引用的方式捕获
return number + x + y; // OK
};
[this] () { // 捕获this指针,可以访问对象内部成员
return number; // OK
};
// [this] () { // 捕获this指针,可访问类内部成员,没有捕获到变量x,y,因此不能访问。
// return number + x + y; // Error
// };
[this, x, y] () { // 捕获this、x、y
return number + x + y; // OK
};
[this] () { // 捕获this指针,可以修改对象内部变量的值
return number++; // OK
};
};
private:
int number = 100;
};
2.2 示例:普通方法中
c
int main() {
int a = 1, b = 2;
[] () { // 未捕获任何变量
return a;
};
[&] () { // 所有外部变量-引用
rturn a++; // OK
};
[=] () { // 所有外部变量-只读
return a; // OK
};
[=] () { // 所有外部变量-只读
return a++; // error
};
[a] () { // a只读
return a + b; // error
};
[a, &b] () { // a只读,b引用
return a + (b++); // OK
};
[=, &b] () { // b引用,其他只读
return a + (b++); // OK
};
}
三、返回值
lambda
表达式的返回值一般都是非常明显的,因此在C++11
中允许省略lambda表达式的返回值
// 完整的lambda定义: auto fun = [] (int parameter) -> int { return parameter + 1; }; // 简化: auto fun = [] (int parameter) { return parameter + 1; };
一般情况下,不指定
lambda
表达式的返回值,编译器会根据return语句自动推导返回值的类型,但需要注意的是lambda
表达式不能通过列表初始化自动推导
出返回值类型。
cauto fun = [] () { return 1; // OK }; auto fun = [] () { // 有多种情况,结构体列表?整形列表? return {1, 2}; //[Error] returning initializer list };
四、option
选项
4.1 mutable
c
void test(int x, int y) {
int a;
int b;
[=, &x] () {
int c = a;
int d = x;
b++; // error
};
}
void test(int x, int y) {
int a;
int b;
[=, &x] () mutable {
int c = a;
int d = x;
b++; // success
};
}
4.2 exception
- 如果有一个函数(可能来自第三方库)会抛出异常,怎么知道它可能抛出的类型呢?
- 查看源码?如果只有函数声明,没有函数实现呢?
- 异常规格说明,是用于说明函数可能抛出的异常种类,作为函数声明的修饰符,跟在参数列表
(parameters)
后面,与静态函数说明const
放在一起。
4.2.1 普通函数:
c
void fun1() throw(); // 表示不抛出任何异常
void fun2() throw(int); // 可能抛出int型异常
void fun3() throw(const char * , float); // 可能抛出C风字符串和单精浮点型异常
void fun4() throw(thread); // 可能抛出thread对象异常
2.2.2 Lambda:
c
[] [] () throw(int, string) {};
五、其他注意事项:
5.1 怎么调用匿名函数?
- 普通函数调用?(
函数名(参数列表)
)
- 在函数后面加上
(parameters)
c
[]() {
cout << 123;
}();
六、Lambda
表达式的本质
-
可以看作是一种可调用对象(普通函数指针?仿函数?)
-
C++中
Lambda
表达式是一个仿函数Lambda
表达式的类型在C++11
中会被看做一个带operator()
的类,即仿函数(重载了operator()
,那么这个类对象都可以作为函数来进行调用,称之为仿函数)C++
标准中,Lambda
表达式的operator()
默认是const
的,一个const
成员函数是无法修改成员变量值的。mutable
关键字的作用就是取消operator()
的const
属性
-
对于没有捕获任何外部变量的匿名函数,可以转换为普通的
函数指针