接着上一篇(第一篇) , 我们还差一种类型的表达式没有介绍 , 那就是lambda表达式的标准格式(后置返回类型的) 。 首先我们先来回顾一下lambda表达式的标准格式
[捕获列表] (参数列表) -> 返回类型 {函数体} 下面我们看一个非常简单的例子:
int main(){
int a = 2 , b = 3 , c = 5;
auto f = [a , b] (int n) -> int {return a + b + n;};
cout << f(c) << endl;
}
既然我们之前都能依靠返回值推断出返回类型 , 为什么还要用后置返回类型 , 下面我们来看一个例子:
int main(){
int a = 2 , b = 3 , c = 5; //上述情况下两个表达是效果相同
// auto f = [a , b] (int n) {if(a + b > n) return a + b + n; else return 0;};
// auto f = [a , b] (int n) -> int {if(a + b > n) return a + b + n; else return 0;};
}
所以如果我们换一种情况:
int main(){
vector<int> vi = {1,4145,3,54,5,3,11,789,5,45,45,6,41,2,78};
transform(vi.begin() , vi.end() , vi.begin() , [] (int n) -> int {if(n > 50) return -n; else if(n > 40 && n < 50) return 0; else return n;});
for(int i : vi){
cout << i << " ";
}
}
输出:
1 -4145 3 -54 5 3 11 -789 5 0 0 6 0 2 -78
使用后只返回类型能够更清楚的告诉编译器和代码阅读者该表达式返回的类型 。
在lambda表达式中 , 还有一种方法能够把所有局部变量都捕获的 , 那就是隐式捕获 , 下面来看一个例子:
int main(){
int a = 2 , b = 3 , c = 5;
auto f = [=] (int n) {return a + b + n;}; //隐式将a和b的值捕获
auto g = [&] (int n) {a = a + n ; b = b - n;}; //隐式将a和b的引用捕获 , 并在函数中改变它们
g(c);
cout << f(c) << endl;
cout << "a: " << a << endl
<< "b: " << b << endl;
}
输出如下:
10
a: 7
b: -2
对于函数f和g , 它们都分别隐式捕获了变量a和b , 而捕获后的规律则和上一篇提到的相同 , 只是这样做会把局部变量全都隐式捕获进来。下面我们看一个更简单的例子:
int main(){
int a = 2 , b = 3 , c = 5;
auto f = [=] () {cout << a + b << endl;};
auto g = [&] () {cout << c << endl;};
}
上述函数都是能通过编译的 , 可是不是说cout不能用值传递吗 , 因为这个对象不能复制 。 其实原因在上一篇已经说过了 , cout的定义并不在这个文件中 , 所以即使不捕获它也能使用 , 而且使用的是它的引用 , 也就是说cout并不是放在捕获列表中的 。
如果只要捕获一个值而其他均为引用 , 或者反之 , 那么应该这样写会更方便:
int main(){
int a = 2 , b = 3 , c = 5;
auto f = [= , &c] () {c = b - a;}; //捕获c的引用和其他变量的值
auto g = [& , c] () {a = c; b = c;}; //捕获c的值和其他变量的引用
f(); g();
cout << "a: " << a << endl
<< "b: " << b << endl
<< "c: " << c << endl;
}
输出:
a: 5
b: 5
c: 1
这个函数就说明了我们可以个对个别例外元素区别对待。
如果我们需要在程序中使用一段形参相同的表达式 , 那么在每个使用的位置都内嵌lambda表达式是一件很费时的事 , 所以我们可以考虑bind函数而不是首选lambda表达式。这里就不对bind函数绑定参数的方法展开了 。