(转载)http://www.cnblogs.com/L-hq815/archive/2012/08/23/2653002.html

lambda表达式

C++ 语言中的lambda表达式在很多情况下提供了函数对象的另一种实现机制。Lambda表达式并不是STL所特有的,但它广泛应用于这一环境中。Lambda是表达式是定义一个没有名称、也不需要显示类定义的函数对象。Lambda表达式一般作为一种手段,用来将函数作为实参传递到另一个函数。相比于定义和创建一个常规的函数对象而言,lambda表达式非常容易使用和理解,而且需要的代码也较少。当然,一般而言,lambda表达式并不会取代函数对象。

举个例子,假设有个包含数值的矢量,我们计算此矢量的立方值。可以用transform()函数操作,简单的用lambda表达式完成。

double  values[] = {1,2,3,4,5,6};
vector<double> data(values,values+6);
vector<double> cubes(data.size());
transform(values.begin(),values.end(),cubes.begin(),[](double x){ return x*x*x;});

最后这条语句用来计算data中的立方值,并存储在cubes。这里简单提一下transform()函数。它是algorithm头文件中的函数,它有两个版本。

第一个版本是将一个一元函数对象指定的操作应用到由一对迭代器指定的一个元素集合上,格式如下:

transform(InputIterator begin, InputIterator end, OutputIterator result,UnaryFuncton f);

transform()的这个版本将一元函数f应用到迭代器begin 和end指定的范围中的所有元素,并从迭代器result指定的位置开始存储结果。Result迭代器可以与begin迭代器相同,只是在这种情况下将会替换原有的内容。这个函数返回一个迭代器,指向存储的最后一个结果的下一个位置。

举例如下:

double  values[] = {1,2,3,4,5,6};
vector<double> data(values,values+6);
transform(values.begin(),values.end(),values.begin(),negate<double>);

transform()函数调用negate<double>函数对象应用到矢量data中的所有元素,结果存储在data中,并重写了原始值,执行完后data将包含 -1,-2,-3,-4,-5,-6。函数返回迭代器data.end()。

transform()第二个版本通过来自迭代器指定的两个范围内的操作数应用一个二元函数。格式为:

transform(InputIterator1 begin1, InputIterator 1end1, InputIterator2 begin2, OutputIterator result,BinaryFunction f);

由begin1和end1指定的范围表示最后一个实参指定的二元函数f的左操作数集合。表示右操作的范围从begin2迭代器指定的位置开始,这个范围不需要提供end迭代器,因为这个范围的元素数量必须与begin1和end1指定的范围元素个数相同,结果从result迭代器位置开始存储在这个范围内。如果希望存回原范围中,result迭代器可以与begin1相同。

举例如下:

double values[]={2.5,-3.5,4.5,-5.5,6.5,-7.5};
vector<double> data(values, values + sizeof values / sizeof values[0]);
vector<double> squares(data.size());
transform(data.begin(),data.end(),data.begin(),squares.begin(),multiplies<double>());
ostream_iterator<double> out(cout,” “);
copy(squares.begin(),squares.end(),out);

Transform()函数通过multiplies<double>函数对象将自身相乘,结果存储到squares中。最后两句用一个输出迭代器输出内容。

现在回到上文:

transform(values.begin(),values.end(),cubes.begin(),[](double x){ return x*x*x;});

开始的方括号称为lambda引导,它标志着lambda表达式的开始。后面的圆括号中的是lambda的参数列表,这与普通函数相同。此例中只有一个形参x。注意,lambda的参数列表不允许指定形参的默认值,并且参数列表的长度是不可变的。大括号中的是lambda的主体,此例只有一条return语句,当然可以包含多条语句。大家可能注意到这里没有返回类型说明。当lambda表达式的主体是一条单一返回语句,而该语句在lambda表达式主体中返回一个值时,返回类型默认为返回值的类型。否则,返回void。当然可以指定返回类型,如下:

[](double x) ->double{ return x*x*x;} //指定返回double

Capture子句

lambda表达式引导可以包含一个捕获子句,用来确定lambda主体如何访问封闭作用域中的变量。前面lambda表达式方括号之间没有内容,表面封闭作用域没有可以再lambda表达式中访问的变量。若要访问,第一种是方括号之间是 = ,则lambda主体可以按值访问封闭作用域的所有自动变量,但不会修改原始变量。另一中是方括号之间是 & ,则封闭作用域的所有自动变量按应用访问,因此lambda表达式可以修改变量值。例如:

double index = 3.0;
double values[] = {1,2,3,4,5,6};
vector<double> data(values,values+6);
vector<double> cubes(data.size());
transform(values.begin(),values.end(),cubes.begin(),
[=](double x){ return index*x*x*x;});

需要主要的是,这与按值传递实参根本不同,变量index的值可用在lambda中,但不能更新index的副本。如:

transform(values.begin(),values.end(),cubes.begin(),
[=](double x) ->double{
index += 10; // error
return index*x*x*x;});

以上是错误的,若要修改变量的临时副本,则通过添加mutable关键字实现。如:

transform(values.begin(),values.end(),cubes.begin(),
[=](double x)mutable ->double{
index += 10; // ok
return index*x*x*x;});

现在可以修改作用域中的任意变量副本,而不会修改原始值。

transform(values.begin(),values.end(),cubes.begin(),
[&](double x)mutable ->double{
index += 10; // change original value
return index*x*x*x;});

现在采用按引用使用,则会改变index的原始值。

若要捕获一个特定的变量,则:

transform(values.begin(),values.end(),cubes.begin(),
[&index](double x)mutable ->double{
index += 10; // change original value
return index*x*x*x;});

这样,只捕获index,如要捕获多个变量,中间用逗号隔开即可。

Lambda也可以包含throw()异常说明,如:

transform(values.begin(),values.end(),cubes.begin(),
[&index](double x)mutable throw()->double{
index += 10; // change original value
return index*x*x*x;});

如果想要包含mutable说明和throw()说明,则中间必须用一个或多个空格隔开。

现在综合看个实例,用以前说过的函数模板实现。

// Using lambda expressions
#include <algorithm>
#include <iostream>
#include <iomanip>
#include <vector>
#include <ctime>
#include <cstdlib>
using namespace std; // Just to avoid a lot of using directives in the example... // Template function to return the average of the elements in a vector
template <class T> T average(const vector<T>& vec)
{
T sum(0);
for_each(vec.begin(), vec.end(),
[&sum](const T& value){ sum += value; });
return sum/vec.size();
} // Template function to set a vector to values beginning with start and incremented by increment
template <class T> void setValues(vector<T>& vec, T start, T increment)
{
T current(start);
generate(vec.begin(), vec.end(),
[increment, &current]()->T{T result(current);
current += increment;
return result;});
} // Template function to set a vector to random values between min and max
template<class T> void randomValues(vector<T>& vec, T min, T max)
{
srand(static_cast<unsigned int>(time(0))); // Initialize random number generator
generate(vec.begin(), vec.end(),
[=](){ return static_cast<T>(static_cast<double>(rand())/RAND_MAX*(max-min)+min); });
} // Template function to list the values in a vector
template<class T> void listVector(const vector<T>& vec)
{
int count = 0; // Used to control outputs per line
for_each(vec.begin(), vec.end(),
[&count](const T& n)->void{ cout << setw(10) << n;
if(++count % 5)
cout << " ";
else
cout << endl;});
} int main()
{
vector<int> integerData(50);
randomValues(integerData, 10, 100); // Set random integer values
cout << "Vector contains:" << endl;
listVector(integerData);
cout << "Average value is "<< average(integerData) << endl; vector<double> realData(20);
setValues(realData, 5.0, 2.5); // Set real values starting at 5.0 ,increment by 2.5
cout << "Vector contains:" << endl;
listVector(realData);
cout << "Average value is "<< average(realData) << endl; return 0;
}

Lambda表达式的包装

Lambda表达式的包装实际上是使用function< >模板赋予lambda表达式一个名字,这不仅提供了在Lambda表达式内递归的可能,而且可以再多条语句使用同样的lambda表达式。如:

Function< int (double)> f = [](double x){ return static_cast<int>(x*x)};

这里具有一个double类型的形参,并返回一个为int类型的值,当然,此处只是举例而已,因为该语句存在问题,将double赋给int时可能会丢失数据。

举例:

#include <iostream>
#include <functional>
using std::function;
using std::cout;
using std::endl; int main()
{
// Wrap the lambda expression to compute the HCF
function<int(int,int)> hcf = [&](int m, int n) mutable ->int{ if(m < n) return hcf(n,m);
int remainder(m%n);
if(0 == remainder) return n;
return hcf(n, remainder);};
int a(17719), b(18879);
cout << "For numbers " << a << " and " << b << " the HCF is " << hcf(a, b) << endl;
a = 103*53*17*97;
b = 3*29*103;
cout << "For numbers " << a << " and " << b << " the HCF is " << hcf(a, b) << endl; return 0;
}

该实例用欧几里得法求两个数的最大公约数,即所谓辗转相除法,采用递归形式实现。

(转载)C++lambda表达式的更多相关文章

  1. Lambda 表达式 学习

    最近几天在学习Lambda,给我的理解就是一个匿名函数的升级版,代码极大可能的简洁了很多,不需要像以前一样必须使用众多的代码才能实现相关功能. 慢慢积累学习,将Java 8的相关知识进行一个学习. 用 ...

  2. 【转载】C++ function、bind和lambda表达式

    本篇随笔为转载,原贴地址:C++ function.bind和lambda表达式. 本文是C++0x系列的第四篇,主要是内容是C++0x中新增的lambda表达式, function对象和bind机制 ...

  3. 转载 C#匿名函数 委托和Lambda表达式

    转载原出处: http://blog.csdn.net/honantic/article/details/46331875 匿名函数 匿名函数(Anonymous Function)是表示“内联”方法 ...

  4. lambda表达式-转载

    来源:http://www.cnblogs.com/knowledgesea/p/3163725.html   前言 1.天真热,程序员活着不易,星期天,也要顶着火辣辣的太阳,总结这些东西. 2.夸夸 ...

  5. Lambda表达式详解(转载)

    原文链接:http://www.cnblogs.com/knowledgesea/p/3163725.html lambda简介 lambda运算符:所有的lambda表达式都是用新的lambda运算 ...

  6. Java 终于有 Lambda 表达式啦~Java 8 语言变化——Lambda 表达式和接口类更改【转载】

    原文地址 en cn 下载 Demo Java™ 8 包含一些重要的新的语言功能,为您提供了构建程序的更简单方式.Lambda 表达式 为内联代码块定义一种新语法,其灵活性与匿名内部类一样,但样板文件 ...

  7. 转载:深入浅出 Java 8 Lambda 表达式

    原文地址:http://viralpatel.net/blogs/Lambda-expressions-java-tutorial/ OneAPM for Java 能够深入到所有 Java 应用内部 ...

  8. 【转载】JDK8 特性 stream(),lambda表达式,

    Stream()表达式 虽然大部分情况下stream是容器调用Collection.stream()方法得到的,但stream和collections有以下不同: 无存储.stream不是一种数据结构 ...

  9. lambda表达式-很好---《转载》

    Lambda表达式详解 前言 1.天真热,程序员活着不易,星期天,也要顶着火辣辣的太阳,总结这些东西. 2.夸夸lambda吧:简化了匿名委托的使用,让你让代码更加简洁,优雅.据说它是微软自c#1.0 ...

随机推荐

  1. 判断webpart类型 How can I tell what type a web part is?

    using(new SPSite("http://mysite/myweb").OpenWeb()){ //give relative path of the webpartpag ...

  2. 我的WebX框架学习总结与心得分享

    最近学习了webx框架, 利用博客园跟大家分享一下自己的学习心得; 周建旭 2014-08-21 网上关于webx的资料少的可怜, 怎么办?  这种情况下不用去求助别人求人只会耽误时间, 不用畏惧; ...

  3. python 记录日志logging

    在项目开发中,往往要记录日志文件.用python记录日志有两种方式: 1.利用python 自带的logging库,例如: # -*- coding: utf-8 -*- import osimpor ...

  4. C#实现IDispose模式

    .net的GC机制有两个问题:首先GC并不能释放所有资源,它更不能释放非托管资源.其次,GC也不是实时的,所有GC存在不确定性.为了解决这个问题.NET提供了析构函数 public class Dis ...

  5. YUV格式详解

    What is YUV YUV,是一种颜色编码方法. YUV是编译true-color颜色空间(color space)的种类,Y'UV, YUV, YCbCr,YPbPr等专有名词都可以称为YUV, ...

  6. SaaS 公司如何应对 On-Call 挑战?

    Cloud Insight 集监控.管理.计算.协作.可视化于一身,帮助所有 IT 公司,减少在系统监控上的人力和时间成本投入,让运维工作更加高效.简单.本文系国内 ITOM 行业领军企业 OneAP ...

  7. VS2005(vs2008,vs2010)使用map文件查找程序崩溃原因

    VS 2005使用map文件查找程序崩溃原因 一般程序崩溃可以通过debug,找到程序在那一行代码崩溃了,最近编一个多线程的程序,都不知道在那发生错误,多线程并发,又不好单行调试,终于找到一个比较好的 ...

  8. C: 数组形参

    知识这个东西,真是知道的越多就不知道的越多,C/C++这塘水得多深啊,哈哈.看下面3个片段:<一> 1 void fun(char a[100]) { 2         fprintf( ...

  9. 服务器部署_linux下部署jprofiler简单备忘

    1.windows安装jprofiler 2.linux下安装jprofiler服务端,记好安装路径.假设是安装在/ex/bin/下 3. 配置tomcat的启动sh文件,在后面加入以下参数:  -a ...

  10. RedMine项目管理系统安装问题(Windows版一键安装包)

    安装准备: 操作环境:VMware10 下安装的windows10 系统 使用软件:<bitnami-redmine---windows-installer.exe> 问题描述: 安装过程 ...