lambda表达式

来源:互联网 发布:sql删除视图数据 编辑:程序博客网 时间:2024/06/05 18:56

谓词

谓词是一个可调用的表达式,其返回结果是一个能用来做条件的值。
接受单一参数的叫一元谓词(unary predicate),接受两个参数的叫二元谓词(bianry predicate)。

可调用对象

对于一个对象或一个表达式,如果可以对其使用调用运算符,则称它为可调用的。(f 是一个可调用的表达式,可以编写代码f(arg) )
四种可调用对象:
1. 函数
2. 函数指针
3. 重载了函数调用运算符的类
4. lambda表达式

lambda表达式

lambda可以理解为一个未命名的内联函数,具体形式如下:
[ capture list ] ( parameter list )  ->return type { function body }

1.返回类型(->return type)

lambda可以根据函数体中代码推断出返回类型,可以忽略返回类型不写,如:
auto f= [] { return 2; }
lambda可以推断返回类型当且仅当函数体中只是一个return语句。如果lambda的函数包含任意单一return 语句之外的内容,且未定返回类型,则返回void。
可以用尾置返回类型指定lambda表达式的返回类型。如:
auto = [] (int i) -> int { if(i>0) return 1; else return -i;};


2.参数列表((parameter list))

与一个普通函数调用类似,调用一个lambda时给定的实参会被用来初始化lambda的形参。
但与普通函数不同,lambda不能有默认参数。
lambda表达式可以忽略参数列表,但忽略了参数列表就要忽略返回类型吗,不然会报错,如:
auto f=[] ->int {return 1;}; //错误auto f=[] {return 1;}; //正确

3.捕获列表([capture list])

一个lambda通过见局部变量包含在其捕获的列表中类指出将会使用这些变量,捕获列表指引lanbda在其内包含访问局部变量所需的信息。

值捕获:

在捕获列表参数前面外加符号。与传值参数类似,采用值捕获的前提是变量可以拷贝,但被捕获的变量的值是在lambda创建时拷贝,而不是在调用时拷贝:
int i=1;auto f=[i] {return i;};i=2;auto temp= f(); //temp值为1

注:这是因为lambda表达式其实是重载函数调用运算符的类。


值捕获变量在函数体中不能改变(隐含的值捕获变量是const),可以使用mutable关键字。用mutable时不能省略参数列表(及时没有参数也要写())

int i=1;auto f=[i] () mutable { i =3; };

引用捕获:

在捕获列表参数前加加&。当以引用方式捕获一个变量时,必须保证在lambda执行时变量时存在的。
int i=1;auto f=[&i]{return i;};i=2;auto temp=f(); //temp值为2;

隐式捕获:

可以让编译器根据lambda体中的代码推断我们要使用哪些变量,为了指示编译器推断捕获列表,应在捕获列表中写一个&或=。
&表示采用引用捕获方式,=表示采用值捕获方式。
int i=1;auto f1=[=]{return i;}//值捕获auto f2=[&]{return i;}//引用捕获
可以混合使用隐式捕获和显示捕获,捕获列表中的第一个元素必须是一个&或=。
当混合使用隐式捕获和显示捕获时,显示捕获的变量必须使用与隐式捕获不同的方式。


lambda捕获列表:

[ ]空捕获列表[ names ]names是一个用逗号分割的名字列表,默认是值捕获,名字前加&使用引用捕获[ & ]隐式引用捕获[ = ]隐式值捕获[ & ,identifier list ]identifier list是一个用逗号分割的列表,只能用值捕获(名字前不能加&)[ = ,identifier list ]identifier list是一个用逗号分割的列表,只能用引用捕获(名字前要加&)


标准库bind函数

lambda使用在只用在一两个地方调用的场景,当要多个地方使用还是要用函数。
解决传递参数长度问题要使用标准库中bind函数。可以将bind函数看成一个通用的函数适配器,它接受一个可调用对象,生成一个新的可调用对象来“适应”原对象的参数列表。
一般形式:
auto newCallable = bind (callable , arg_list)
arg_list中参数包含_n的占位符,表示占据传递给newcallable的参数的位置。如:
auto g= bind(fun,a,b,_2,c,_1);
当调用g时,如:
g(g1,g2);
映射为:
fun(a,b,g2,c,g1);
注意:bind函数和lambda一样,在绑定时就拷贝对象,不是在调用时才拷贝。
int temp=1;auto g=bind(fun,temp,_1);temp=2;g(2);  //->fun(temp,2) temp值为1 

函数头文件为<functional> , _n 定义在std::placeholders::_n 中

绑定引用参数

需使用ref函数,const引用用cref函数。
auto g=bind(fun,_1,ref(a),cref(b));
ref和cref都定义在<functional>头文件中。