Chinaunix首页 | 论坛 | 博客
  • 博客访问: 624710
  • 博文数量: 79
  • 博客积分: 848
  • 博客等级: 军士长
  • 技术积分: 1800
  • 用 户 组: 普通用户
  • 注册时间: 2012-06-26 19:30
文章分类

全部博文(79)

文章存档

2015年(4)

2013年(39)

2012年(36)

分类: C/C++

2013-03-19 16:31:35

当我第一听到这个概念的时候,第一反应想到的是离散数学中闭包的概念:若在一个集合上进行某种运算,其运算结果仍为集合中的元素,则称该集合为此运算上的闭包。
那么什么是编程语言中的闭包呢?我是一头雾水,网络达人有语:“外事不明问谷歌,内事不明问百度!”,英语向来差劲的在下,就先去找度娘商议了一番,度娘给出如下回答:
闭包是可以包含自由(未绑定到特定对象)变量的代码块;这些变量不是在这个代码块内或者任何全局上下文中定义的,而是在定义代码块的环境中定义。“闭包” 一词来源于以下两者的结合:要执行的代码块(由于自由变量被包含在代码块中,这些自由变量以及它们引用的对象没有被释放)和为自由变量提供绑定的计算环境 (作用域)。在 Scala、Scheme、Common Lisp、Smalltalk、Groovy、JavaScript、Ruby 和 Python,objective c 等语言中都能找到对闭包不同程度的支持。
度娘向来如此文艺,说的我是一知半解,到底神马意思呢?
我们还是举个例子来表达之:

点击(此处)折叠或打开

  1. /*************************************************************************
  2.     > File Name: lambda.cpp
  3.     > Author: dongdaoxiang
  4.     > Mail: dongdaoxiang@ncic.ac.cn
  5.     > Created Time: 2013年03月19日 星期二 11时31分42秒
  6.  ************************************************************************/

  7. #include<iostream>
  8. #include<vector>
  9. using namespace std;
  10. int main()
  11. {
  12.     int temp = 10;
  13.     vector<int> ivec = {30, -10, -20, 50, 40 ,100, -50};
  14.     vector::iterator it = ivec.begin();
        while(it != ivec.end())
        {
            cout << *it << endl;
            it++;
        }
  15.     return 0;
  16. }
我们要对于vector容器中的一系列元素进行处理,这里只是举个简单的例子就是遍历容器中的每一个元素,我们需要像上面的代码中那样,写一个循环然后加入我们处理的代码(这可能是我们一贯的思想),但是这样做存在两个问题:
1、代码的复用性不强,如果下次我们还要遍历另外的一个容器的时候,我们还要重复这里我们的工作。
2、这样写起来太繁琐。
这个时候,有人举手了!说我门可以使用c++的algorithm库内的函数来完成我们操作!于是乎就有了下面的代码:

点击(此处)折叠或打开

  1. /*************************************************************************
  2.     > File Name: lambda.cpp
  3.     > Author: dongdaoxiang
  4.     > Mail: dongdaoxiang@ncic.ac.cn
  5.     > Created Time: 2013年03月19日 星期二 11时31分42秒
  6.  ************************************************************************/

  7. #include<iostream>
  8. #include<vector>
  9. #include<algorithm>
  10. using namespace std;
  11. class printInt
  12. {
  13.     public:
  14.     void operator()(const int x)
  15.     {
  16.         cout << x << endl;
  17.     }
  18. };

  19. int main()
  20. {
  21.     int temp = 10;
  22.     vector<int> ivec = {30, -10, -20, 50, 40 ,100, -50};
  23.     std::for_each(ivec.begin(), ivec.end(), printInt());
  24.     return 0;
  25. }
wow,看起来真的很酷,这样一来就把遍历的操作和输出的操作剥离开了,极大的增强了我们代码的复用性,从而简化了我们编程!假如,我们的需求仅仅是遍历并且输出容器中的每个元素的话,这可以说是一个完美的解决方案!但是我又有了这样的需求我不仅仅想要输出它,我还想对里面的元素进行排序,stl大侠又说了这不难看我的:

点击(此处)折叠或打开

  1. #include<iostream>
  2. #include<vector>
  3. #include<algorithm>
  4. using namespace std;
  5. class printInt
  6. {
  7.     public:
  8.     void operator()(const int x)
  9.     {
  10.         cout << x << endl;
  11.     }
  12. };

  13. int main()
  14. {
  15.     int temp = 10;
  16.     vector<int> ivec = {30, -10, -20, 50, 40 ,100, -50};
  17.     std::sort(ivec.begin(), ivec.end());
  18.     std::for_each(ivec.begin(), ivec.end(), printInt());
  19.     return 0;
  20. }
wow,我大模板果然强大,碉堡了!碉堡了!高兴之余,新的需求又来了,我想要对容器中元素按照绝对值进行排序,而且这次不仅仅是排序了,我还想要让其中每一个元素加上一个局部的变量temp,没错这对于经常写代码的人来说,也不难实现,我们可以写一个绝对值排序的函数,如下:

点击(此处)折叠或打开

  1. #include<iostream>
  2. #include<vector>
  3. #include<algorithm>
  4. using namespace std;
  5. void abs_sort(vector<int> &ivec, int i, int j )
  6. {
  7.     if(i < j)
  8.     {
  9.         int left = i;
  10.         int right = j;
  11.         int rawData = ivec[left];
  12.         int flag = abs(ivec[left]);
  13.         while(left < right)
  14.         {
  15.             while(left < right && abs(ivec[right]) > flag)
  16.             {
  17.                 right--;
  18.             }
  19.             ivec[left] = ivec[right];
  20.             while(left < right && abs(ivec[left]) <= flag)
  21.             {
  22.                 left++;
  23.             }
  24.             ivec[right] = ivec[left];
  25.         }
  26.         ivec[left] = rawData;
  27.         abs_sort(ivec, i, left - 1);
  28.         abs_sort(ivec, left + 1, j);
  29.     }
  30. }
  31. class printInt
  32. {
  33.     public:
  34.     void operator()(const int x)
  35.     {
  36.         cout << x << endl;
  37.     }
  38. };

  39. int main()
  40. {
  41.     int temp = 10;
  42.     vector<int> ivec = {30, -10, -20, 50, 40 ,100, -50};
  43.     //std::sort(ivec.begin(), ivec.end());
  44.     abs_sort(ivec, 0, ivec.size() - 1);
  45.     vector::iterator it = ivec.begin();
  46.     while(it != ivec.end())
        {
  47.         *it += temp;
            cout << *it << endl;
            it++;
        }
  48.     return 0;
  49. }
恩,不错这样的确实现了我们需求,但是这里我们会发现我们又回到了第一个程序上面,将遍历和操作捆绑在了一起,而且需求我们自己手动写大量的代码,例如上面的abs_sort,这个放在以前好像的确没有什么更好的办法了,但是c11横空出世了,于是就有了下面的实现:

点击(此处)折叠或打开

  1. /*************************************************************************
  2.     > File Name: lambda.cpp
  3.     > Author: dongdaoxiang
  4.     > Mail: dongdaoxiang@ncic.ac.cn
  5.     > Created Time: 2013年03月19日 星期二 11时31分42秒
  6.  ************************************************************************/

  7. #include<iostream>
  8. #include<vector>
  9. #include<algorithm>
  10. using namespace std;

  11. int main()
  12. {
  13.     int temp = 10;
  14.     vector<int> ivec = {30, -10, -20, 50, 40 ,100, -50};
  15.     std::sort(ivec.begin(), ivec.end(), [](const int &x, const int &y) {return abs(x) < abs(y);});
  16.     std::for_each(ivec.begin(), ivec.end(), [&](int &x) { x += temp; cout << x << endl;});
  17.     return 0;
  18. }
还等什么呢?撒花吧!颤抖吧!骚年们,这是c11的lambda带给我们的一个惊喜,这不仅仅是几行代码哦,这标志着c++也像Ruby、Python等时下流行的语言一样支持”闭包“了,虽然他有另外的一个名字:“lambda”!!让我们赶紧认识一个这个新朋友吧!
Lambda表达式是一种描述函数对象的机制,它的主要应用是描述某些具有简单行为的函数(译注:Lambda表达式也可以称为匿名函数,具有复杂行为的函数可以采用命名函数对象,当然,简单和复杂之间的划分依赖于编程人员的选择)。
上面的例子中参数 [](const int &x, const int &y) { return abs(x) < abs(y); }是一个"lambda"(又称为"lambda函数"或者"lambda表达式"), 它描述了这样一个函数操作:接受两个整形参数a和b,然后返回对它们的绝对值进行"<"比较的结果。
[&] 是一个“捕捉列表(capture list)”,用于描述将要被lambda函数以引用传参方式使用的局部变量。如果我们仅想“捕捉"参数v,则可以写为: [&v]。而如果我们想以传值方式使用参数v,则可以写为:[=v]。如果什么都不捕捉,则为:[]。将所有的变量以引用传递方式使用时采用 [&], [=] 则相应地表示以传值方式使用所有变量。(译注:“所有变量”即指lambda表达式在被调用处,所能见到的所有局部变量)
这意味着什么,我们不用向以前c语言中的高阶函数那样,通过函数指针来传递函数的操作了,而指针的操作往往就是c/c++中99%的坑的来源!他可以在局部大函数里面访问环境中的局部变量,多么cool和powerful的功能!

为了描述一个lambda,你必须提供:

  • 它的捕捉列表:它可以使用的变量列表(除了形参之外),如果存在的话("[&]" 在上面的记录比较例子中意味着“所有的局部变量都将按照引用的方式进行传递”)。如果不需要捕捉任何变量,则使用 []。
  • (可选的)它的所有参数及其类型(例如: (int a, int b) )。
  • 组织成一个块的函数行为(例如:{ return v[a].name < v[b].name; })。
  • (可选的)采用了新的后缀返回类型符号的返回类型。但典型情况下,我们仅从return语句中去推断返回类型,如果没有返回任何值,则推断为void。

总结一下吧:本文简单的介绍了一下对于c11标准中新增的lambda表达的式的一些个看法,完全出自一家之言,如有不恰当的地方欢迎批评指正,如有雷同实属巧合!!
本文参考一下前辈的博文:



阅读(7056) | 评论(8) | 转发(3) |
给主人留下些什么吧!~~

风箫夜吟2013-03-21 09:11:36

niao5929:呵呵,现在看来n年以前的理论在强势回归呀!

文明上网,理性发言...

回复 | 举报

niao59292013-03-21 07:06:11

呵呵,现在看来n年以前的理论在强势回归呀!

niao59292013-03-21 07:06:07

呵呵,现在看来n年以前的理论在强势回归呀!

niao59292013-03-21 07:05:54

呵呵,现在看来n年以前的理论在强势回归呀!

风箫夜吟2013-03-20 20:49:07

Bean_lee:对于这个feature,Lisp笑而不语,呵呵

是的……Lisp相比来说,在这方面的确比较牛逼,但是LISP的宏让人有些蛋疼

回复 | 举报