我们可以向一个算法传递任何类别的可调用对象。
C++语言中有几种可调用的对象:函数、函数指针、lambda表达式,bind创建的对象以及重载了函数调用运算符的类。
lanmbda必须使用尾置返回来指定返回类型。
它必须要包含捕获列表和函数体。
auto f = [] {return 79;}; //这是一个lambda表达式,大括号里面的分号不能忘记了
cout<<f()<<endl; //调用它输出79
如果 lambda 的函数体包含任何单一 return 语句之外的内容,且未指定返回类型,则会返回 void。
如果函数体只有return 语句,返回类型从返回的表达式的类型推断而来。
lambda 不能有默认参数,它调用的实参数目永远与形参数目相等。、
auto Show = [] (int x ) {cout<<x+10<<endl;};
Show(10);//也可以像这样调用,输出20
[] (int x ) {cout<<x+10<<endl;}(20);//可以像这样调用它,输出30
使用捕获列表:
一个 lambda 只有在其捕获列表中捕获一个它所在函数中的局部变量,才能在函数体中使用该变量。(不能没有捕获就使用变量,会编译错误)
捕获列表只用于局部非 static 变量,lambda 可以直接使用局部 static变量和在它所在函数之外声明的名字。
auto c = [] (int n )
{
return [n] (int x)//这里捕获了前一个lambda表达式的形参 n
{
return n+x;
};//这里的分号不能忘记了
};
//int f = c(5)(5);
cout<<c(5)(5)<<endl;//输出10
lambda 表达式可能嵌套使用。
使用尾置返回来指定返回类型。
auto c1 = [] (int a , int b ) -> int {//用尾置返回来指定返回类型
return a+b;
}(1,2);
cout<<c1<<endl;//输出3
int u1 = 200;//要想在lambda中使用变量u1必须要用捕获列表捕获
static int u = 100;//而这个可以直接在lambda中使用,可以不用捕获
auto c1 = [&u1] (int a , int b ) -> int {//用尾置返回来指定返回类型
return a+b+u+u1;
}(1,2);
cout<<c1<<endl;//输出3
捕获分为 值捕获 和 引用捕获:
值捕获:
int u = 100;
auto f = [u] {return u+100;};
cout<<f()<<endl;//输出 200
cout<<u<<endl;//输出100
使用值捕获的变量的值是在 lambda 创建时拷贝,而不是调用拷贝。
引用捕获:
int u = 100;
auto f = [&u] {return u+100;};//用值捕获方式捕获并不会改变变量本身的值
cout<<f()<<endl;//输出 200
cout<<u<<endl;//输出100
使用引用捕获的变量实际是引用所绑定的对象。
当以引用方式捕获一个变量时,必须保证在 lambda 执行时变量是存在的。
我们可以使用 & 告诉编译器采用捕获引用方式, = 表示采用值捕获方式。
auto f = [&] {return u+100;};
auto f1 = [=] {return u+100;};
还可以混合使用:
int u = 100 , p = 200;
auto f = [& , u] {return u+p+100;};//这个表示 p 是隐式捕获,引用捕获 ;c是显示捕获,值捕获方式
auto f1 = [= , & u] {return u+p+100;}; //这个表示 u 是显式引用捕获方式;p 是隐式捕获,值捕获
当我们混合使用隐式捕获和显式捕获的时候,捕获列表中的第一个元素必须是一个 & 或 = 。这个符号指定了默认捕获方式。并且显式捕获的变量必须使用与隐式捕获不同的方式,如果隐使用 & 则显式必须要用 = ;反之一样。
可变 lambda:
默认情况下 lambda 不会改变捕获变量本身的值。如果希望需要更改变必须在参数列表首加上关键字 mutable ,可变 lambda 能省略参数 列表:
int u = 100 , p = 100;
auto f = [&u] (int &x) mutable {return x+100;};
cout<<u<<endl;//输出100
cout<<f(p)<<endl;//输出200
cout<<p<<endl;//输出100
无论如何改变都是改变 lambda 内部的值,不会改变外面本身的值。
记住要指定 lambda 的返回类型要用尾置返回类型。