隐式捕获:
出了显式列出我们希望使用的来自函数的变量外,还可以让编译器根据lambda体中的代码来推断我们要使用哪些变量。为了指示编译器推断捕获列表,应在捕获列表中写一个&或=。&告诉编译器采用引用捕获方式,=告诉编译器采用值捕获方式。我们可以混合使用隐式或显式捕获,在此条件下,捕获列表的第一个元素必须是一个&或=。当混合使用隐式和显式捕获时,显式捕获的变量必须使用与隐式捕获不同的方式。即,如果隐式捕获时引用(&)方式,则显式捕获名变量必须使用值捕获方式,因此不能在显式捕获名字前使用&;如果是隐式捕获时值(=)方式,显式捕获变量名必须采用引用方式,即在名字前加&。
eg:
1 #include2 using namespace std; 3 4 int main() 5 { 6 /*隐式引用捕获*/ 7 int ma = 10; 8 int mma = 10; 9 auto f= [&] { return ma+mma; };10 ma = 1;11 cout << f() << endl;12 13 /*隐式值捕获*/14 int a = 10;15 int aa = 10;16 auto ff = [=] { return a+aa; };17 a = 1;18 cout << ff() << endl;19 20 /*混合捕获,引用在前*/21 int i = 10;22 int j = 100;23 auto fff = [&,j] { return i+j; };24 //auto fff = [&i, =] {return i + j; }; err25 //auto fff = [&i, &] {return i + j; }; err26 i = 1;27 cout << fff() << endl;28 29 /*混合捕获,值在前*/30 int m = 10;31 int n = 100;32 auto ffff = [=, &n] { return m + n; };33 n = 1;34 cout << ffff() << endl;35 36 /*混合捕获的思考,多个变量,可以隐式捕获,针对特殊变量,单独指定*/37 int q = 1, w = 10, e = 20, r = 30;38 /*我想除了e变量,其余的都用值捕获*/39 auto fffff = [=, &e] { return q+w+e+r; };40 e = 100;41 cout << fffff() << endl;42 return 0;43 }
可变lambda:
默认情况下,对于一个值拷贝的变量,lambda不会改变其值,如果我们希望能改变一个被捕获的变量的值,就必须在参数列表后加上mutable。因此,可变lambda能省略参数列表。
1 #include2 using namespace std; 3 4 int main() 5 { 6 int ma = 10; 7 auto f= [=] ()mutable { return ++ma; }; 8 cout << f() << endl; 9 return 0;10 }
一个引用捕获能否改变变量的值依赖于此引用指向的是一个const类型还是一个非const类型。
指定lambda返回类型:
默认情况下,如果lambda体包含return之外的任何语句,则编译器假定此lambda返回void。与其他返回void的函数类似,被推断返回void的lambda不能返回值。
1 #include2 using namespace std;3 4 int main()5 {6 auto f = [](int* a)->int * { if (*a > 0)return a; else return NULL; };7 cout << f(NULL) << endl;8 return 0;9 }
不用位置返回类型将报错。但是如果返回类型都是一种类型,比如上诉两个return,都return一种类型,是可以推断的,但是吐过return类型不同,将要使用尾置返回类型强制指定,在不止单纯一条return语句时,建议最好使用尾置返回类型。
对于那种只在一两个地方使用的简单操作,lambda表达式是很有用的。但如果我们需要在很多地方使用相同的操作,通常应该定义一个函数,而不是多次编写相同的lambda表达式。类似的,如果一个操作需要很多语句完成,通常使用函数更好。如果一个lambda捕获列表为空,通常可以用函数来代替它。但是对于捕获局部变量的lambda,用函数替代就不那么容易了。