此文为本人的原创翻译,转载请注明作者及版权信息!!
翻译:李波
Email: [email protected]
Lambda表达式和闭包,part1
C++标准委员会在2008年2月的Bellevue会议上通过了lambda的提议,最新版本的提议与我2005年在这里展示有很大不同。
术语已经修改了,像语法,语义,使用,以及lambda的实现。在这个系列的第一部分我会介绍最新lambda表达式的概念和原理。
为什么使用lambda表达式?
一个lambda表达式(也称lambda函数)就是一个定义在调用那里的无名函数。就其本身而言,它和函数对象非常相似。的确,lambda表达式是被自动转换成函数对象的;那为什么不直接使用函数对象呢?也许lambda表达式更好用,创建函数对象是非常费劲的:有必须定义一个类和它的数据成员,一个重载函数调用operator和构造函数。然后你必须在所有调用的地方实例化那个类型的对象。这是非常繁琐的。
为了演示lambda的长处,假设你必须找到第一个员工,他的工资在给定的范围内;使用传统繁琐的函数对象,你可以写一个withinrange class:
class withinrange { double low, high; public: withinrange(double l, double h) : low(l), high(h) { } bool operator()(const employee& emp) { return emp.salary() >= low && emp.salary() < high; } };接下来,使用find_if算法来定位第一个工资在指定范围的员工:
double minimum_salary=1000;
std::find if(employees.begin(), employees.end(),
withinrange(minimum_salary, 1.25* minimum_salary));
使用Lambda 表达式:
使用新的lambda表达式,上面的find_if可以这样重写:
double minimum_salary = 1000; double upper_limit = 1.25 * minimum_salary; std::find if(employees.begin(), employees.end(), [&](const employee& emp) (emp.salary() >= minimum_salary && emp.salary() < upper_limit));
Lambda表达式用[]作为开始的标志(我会在以后的系列中讨论[]中&的含义),[]后面是lambda表达式的参数列表,在这个例子中,参数列表有唯一的参数const employee&组成,整个lambda表达式可以说是单一的,因为它的参数列表被显式指定的,这里,单一的参数类型是const employee&,同样的lambda表达式多态版本可以这样写:
[&](emp) (emp.salary() >= minimum_salary && emp.salary() < upper_limit)
隐式和显式的返回类型
前一个lambda表达式的最后一部分:
(emp.salary() >= minimum_salary && emp.salary() < upper_limit)
(emp.salary() >= minimum_salary && emp.salary() < upper_limit)
从技术上讲,如果返回类型没有显式的指定,返回类型被定义为decltype(e),e 是在函数体内调用的;但你也可以显示的指定lambda表达式的返回类型;借助新的函数声明语法,我们可以这样写:
[&](emp) ->bool (emp.salary() >= minimum_salary && emp.salary() < upper_limit)
一个lambda表达式的函数体可以包含多条语句,在这种情况下,函数体由一对大括号包住(和我们普通的函数体一样)并且必须有显式的返回语句;下面的lambda表达式有两个int类型参数和一个int类型的返回值,函数体有有三条语句组成和大括号组成:
[](int x, int y) -> int { int z; z = x + y; return z; }
外部引用
lambda表达式被分为两个大的种类:无外部引用和有外部引用,后者(外部引用)用来访问定义在lambd表达式参数列表外的变量,相反的,无外部引用的表达式不访问定义在lambd表达式参数列表外的变量;
无外部引用的lambda表达式的例子:
[](int x, int y) -> int { return x + y; }
有外部引用的例子:
int z; myfunc([](int x, int y) -> int { return x + y + z; } );//pseudo code
引用定义在lambda表达式外的局部变量已经争论了很长时间了,问题是在lambda函数体内引用的局部变量必须以某种方式保存在结果闭包里,比如前面的这个例子;这些变量是怎样保存在闭包里是争议的问题;一些人建议使用外部变量的拷贝保存在闭包里,然后拷贝在一些情况下是低效的,并有可能导致变量切片(译者注:比如类)和迭代器失效,其他方案建议保存这些变量的引用,这种方法也可以是静态的因为它可能导致悬挂引用。在这个系列第二个部分我会show最新的方案怎么样解决外部引用问题和外部引用在闭包怎样表现的。
欢迎大家发表自己的看法和见解,我们一起讨论,文中有不足之处,也请指出,多谢了
第二部分正在翻译,待续。。。