一、lambda表达式

lambda表达式原型: [capture list] (parameter list) -> retrue type { function body }
一个lambda表达式表示一个可调用的代码单元,可以理解为一个未命名的内联函数。一个lambad表达式包含 : 一个捕获列表,一个参数列表,一个返回类型和函数体。
但与函数不同的是,lambda可能定义在函数内部。 lambda可以忽略参数列表和返回类型,但必须包含捕获列表和函数体。 
如果一个lambda的函数体包含任何单一的return语句之外的内容,且未指定返回类型,则返回void
1. 捕获列表
lambda的捕获列表只用于局部的非static变量,它可以直接使用局部static变量和它所在函数之外声明的名字。lambda只有在其捕获列表中捕获了一个它所在函数中的局部非static变量,它的函数体才可以使用该变量。
捕获方式有两种 : 值捕获和引用捕获 另外还有 隐式捕获
值捕获 : 和传值参数类似,lambda进行值捕获的时候拷贝变量,与参数不同,lambda的值捕获进行拷贝时是创建时拷贝,而不是调用时拷贝。
引用捕获:引用捕获和引用传递参数类似,不拷贝变量,但应该注意的是,我们lambda在进行引用捕获时,要确保被引用的对象在lambda执行的时候是存在的。
 
隐式捕获 : 值捕获和引用捕获都是显示列出了我们想要捕获的变量,我们还可以让编译器根据lambda体中的代码来推断我们要使用哪些变量,我们需要在捕获列表里写一个 & 或者 =。 &告诉编译器采用引用捕获方式,= 是值捕获方式。还可以混合使用显示和隐式捕获方式。
当我们混合使用显示和隐式捕获方式时,捕获列表中的第一个元素必须是一个&或=, 指定默认的捕获方式为值或引用。  而且显示捕获的变量必须使用与隐式捕获不同的凡是。如果隐式捕获时引用方式,则显示捕获必须是值方式。
lambda捕获列表
                 [ ] 空捕获列表,lambda不能使用所在函数中的变量
            [names] names是一个逗号分隔的名字列表,都是lambda所在函数的变量,默认情况下,捕获列表中的变量都被拷贝
                [&] 隐式捕获列表,采用引用捕获方式。lambda体中所使用的来自所在函数的实体都采用引用方式使用
                [=] 隐式捕获列表,采用值捕获方式。lambda体中所使用的来自所在函数的实体都采用饮用方式使用
                                                                                                                             [&,identifer_list]                          identifer_list是一个逗号分隔的名字列表,包含0个或多个来自所在函数的变量,这些变量都采用值捕获方式,而不在这些列表中的变量则使用引用捕获方式, identifer_list中变量前不能使用&
                                             [=,identifer_list]  identifer_list是一个逗号分隔的名字列表,包含0个或多个来自所在函数的变量,这些变量都采用引用捕获方式,而不在这些列表中的变量则使用值捕获方式,identifer_list中的名字不能包括this,且这些名字前必须使用&

默认情况下,值捕获的变量,lambda不会改变其值,如果我们希望改变一个被值捕获的变量,就把关键字 mutable 跟随在参数列表后
void func(){
size_t i = 0;
auto f = [i] () mutable { return ++i; }
cout << "i = " << i << endl;
}

输出 i = 1

2. 指定lambda返回类型
前面我们说,如果一个lambda的函数体包含任何单一的return语句之外的内容,且未指定返回类型,则返回void。
transform(v.begin(), v.end(), v.begin(), [] (int i) {if (i < 0) return -i; else return i;})

这段程序将产生错误,因为编译器推断出lambda返回一个void,但它返回一个int值。

我们需要使用尾置返回类型来指定lambda的返回类型:
transform(v.begin(), v.end(), v.begin(), [] (int i) -> int {if (i < 0) return -i; else return i;})

二、参数绑定 bind函数

标准库bind函数定义在头文件 <functional>中,它接受一个可调用对象,来生成一个新的可调用对象来适用原对象的参数列表。
调用bind的一般形式为:
auto newCallable = bind(callable, arg_list);

newCallable本身是一个可调用对象,arg_list是一个逗号分隔的参数列表,对应给定的callable的参数。当我们调用newCallable时,newCallable会调用callable,并传递给callable对应的参数arg_list。

 arg_list中会出现形如 _n的名字,n是一个整数,从1开始。这些参数是"占位符", 表示newCallable的参数。它们占据了传递给newCallable的参数的位置,数值n表示生成的可调用对象中参数的位置。
名字 _n 都定义在一个名为placeholders的命名空间里,而这个命名空间则包含在std命名空间里。我们要用这些占位符时,就需要using声明:
using std::placeholders::_n

与bind一样,placeholders命名空间也定义在 <functional> 头文件中。
bind的参数 
例:
// g是一个有两个参数的可调用对象
auto g = bind(f, a, b, _2, c, _1);

这样一来,我们传递给g对象的参数,按位置绑定到占位符上,第一个参数绑定到_1, 第二个绑定到_2.

实际上,这个bind调用会将  g(_1, _2) 映射为 f (a, b, _2, c, _1),例如调用g(X, Y)会调用 f (a, b, Y, c, X)
默认情况下,bind的那些不是占位符的参数被拷贝到返回的可调用对象中。对有些绑定的参数我们希望以引用方式传递,或是要绑定参数的类型无法拷贝。
// 错误,不能拷贝os
for_each(words.begin(), words.end(), bind(print, os, _1, ' '));

我们不能拷贝一个ostream对象,如果我们希望传递给bind一个对象但不拷贝它,就必须使用标准库ref函数。

函数ref返回一个对象,包含给定的引用。还有一个cref函数,生成一个const引用的类。ref和cref函数也定义在 <functional>头文件中。

C++ Primer : 第十章 : 泛型算法 之 lambda表达式和bind函数的更多相关文章

  1. C++ Primer : 第十章 : 泛型算法 之 只读、写和排序算法

    大多数算法都定义在<algorithm>头文件里,而标准库还在头文件<numeric>里定义了一组数值泛型算法,比如accumulate. ●  find算法,算法接受一对迭代 ...

  2. lambda表达式与bind函数

    #include<iostream> #include<algorithm> #include<sstream> #include<vector> #i ...

  3. C# 委托 (一)—— 委托、 泛型委托与Lambda表达式

    C# 委托 (一)—— 委托. 泛型委托与Lambda表达式 2018年08月19日 20:46:47 wnvalentin 阅读数 2992   版权声明:此文乃博主之原创.鄙人才疏,望大侠斧正.此 ...

  4. kotlin之lambda表达式和匿名函数

    lambda表达式,称为匿名函数,是一种函数字面值,也就是没有声明的函数,但可以作为表达式传递出去. 函数类型: 对于接受另一个函数的作为自己的参数,必须针对这个参数指定一个函数的类型如 fun &l ...

  5. Python函数与lambda 表达式(匿名函数)

    Python函数 一.函数的作用 函数是组织好的,可重复使用的,用来实现单一或相关联功能的代码段 函数能提高应用的模块性和代码的重复利用率 python 内置函数:https://docs.pytho ...

  6. C# 委托(delegate)、泛型委托和Lambda表达式

    目录 # 什么是委托 # 委托声明.实例化和调用 1.声明 2.委托的实例化 3.委托实例的调用 4.委托完整的简单示例 #泛型委托 1.Func委托 2.Action委托 3.Predicate委托 ...

  7. Lambda表达式公共拼接函数(原创)

    #region Lambda公共拼接函数 /// <summary> /// LambdaWhere(枚举) /// </summary> public enum Lambda ...

  8. 第三天 函数 三元运算 lambda表达式 内置函数 文件操作

    面向过程: 直接一行一行写代码,遇到重复的内容复制黏贴. 不利于代码阅读 代码没有复用 面向对象 将代码块定义为函数,以后直接调用函数 增强了复用性 函数的定义方法 def 函数名(传递参数): 函数 ...

  9. lambda表达式,map函数

    lambda只是一个表达式,不需要定义函数,故也是匿名函数,用法为:lambda 参数:表达式. x=5 list1=[2,3,4] list2=[10,20,30] s=lambda x:x**3 ...

随机推荐

  1. 主机无法访问虚拟机上的elasticsearch服务器

    问题: es在linux上搭建好,通过curl -XGET ip:port可以获得服务器信息展示,但是主机在浏览器上无法访问. 原因: 主机通过telnet访问linux的80端口,发现是不通的.可以 ...

  2. Codeforce385C 树状数组+素因子分解

    题目大意: 给多个区间的询问,在询问区间内每一个出现的素数去计算所有数中有多少个数能被这个素数整除 然后将所有素数得到的对应值求和 这里因为初始给定的数不超过10000000,最多670000不到的素 ...

  3. getSingleResult 和 selectone

    都是返回一个对象,如果找到一个以上的对象会报错,这个在登录验证和添加的时候可能会有点小用,因为登录和添加的时候都要判断是不是数据库有这个username,登录的时候希望有,添加的时候希望没有,但是两者 ...

  4. Oracle数据库中序列用法讲解

    序列(SEQUENCE)是序列号生成器,可以为表中的行自动生成序列号,产生一组等间隔的数值(类型为数字).其主要的用途是生成表的主键值,可以在插入语句中引用,也可以通过查询检查当前值,或使序列增至下一 ...

  5. hdu 2092

    Ps:wa了两次....一次是从加法那边暴力,然而算法错误..应该从乘法那边暴力破解...然而又没算负数..加上负数..直接暴力AC. 代码: #include "stdio.h" ...

  6. hdu 2089

    PS:额...暴力打表...今天学到的新名词..记得把数组开到100W.. 代码: #include "stdio.h" ]; int cal(int a); int main() ...

  7. 5分钟学习maven(根据英文文档整理)

    英文原地址:http://maven.apache.org/guides/getting-started/maven-in-five-minutes.html 一.前提 需要懂得如何在计算机上安装软件 ...

  8. UIWebView stringByEvaluatingJavaScriptFromString的使用方法

    stringByEvaluatingJavaScriptFromString 使用stringByEvaluatingJavaScriptFromString方法,需要等UIWebView中的页面加载 ...

  9. ios工程中ARC与非ARC的混合

    ARC与非ARC在一个项目中同时使用, 1,选择项目中的Targets,选中你所要操作的Target,2,选Build Phases,在其中Complie Sources中选择需要ARC的文件双击,并 ...

  10. 前App Store高管揭秘:关于“苹果推荐”的七大真相

    相信你已经看过很多这样那样关于如何获得苹果商店推荐的攻略了,但其实很多人依然陷入了很大的误区.前不久采访了前App Store团队高管Greg Essig,向各位开发者揭示关于获得苹果推荐的真相. 在 ...