C++11 Lambda表达式

本文根据众多互联网博客内容整理后形成,引用内容的版权归原始作者所有,仅限于学习研究使用,不得用于任何商业用途。

C++11引入了lambda表达式,使得程序员可以定义匿名函数,该函数是一次性执行的,既方便了编程,又能防止别人的访问。
Lambda表达式的语法通过下图来介绍:



这里假设我们定义了一个如上图的lambda表达式。现在来介绍途中标有编号的各个部分是什么意思。

  • Lambda表达式的引入标志,在‘[]’里面可以填入‘=’或‘&’表示该lambda表达式“捕获”(lambda表达式在一定的scope可以访问的数据)的数据时以什么方式捕获的,‘&’表示以引用的方式;‘=’表明以值传递的方式捕获,除非专门指出。
  • Lambda表达式的参数列表
  • Mutable 标识
  • 异常标识
  • 返回值
  • “函数”体,也就是lambda表达式需要进行的实际操作

Lambda表达式是一种描述函数对象的机制,它的主要应用是描述某些具有简单行为的函数(译注:Lambda表达式也可以称为匿名函数,具有复杂行为的函数可以采用命名函数对象,当然,何谓复杂,何谓简单,这取决于编程人员的个人选择)。例如:

vector<int> v = {50, -10, 20, -30};
std::sort(v.begin(), v.end()); // 排序时按照默认规则
// 此时v中的数据应该是 { -30, -10, 20, 50 }

// 利用Lambda表达式,按照绝对值排序
std::sort(v.begin(), v.end(), [](int a, int b){ return abs(a)<abs(b); });
// 此时v应该是 { -10, 20, -30, 50 }

函数 [](int a, int b) { return abs(a) < abs(b); }
是一个具有如下行为的"lambda":接受两个整数a和b,然后返回对它们的绝对值进行"<"比较的结果。
Lambda表达式可以访问在它被调用的作用域内的局部变量。例如:

void f(vector<Record>& v)
{ 
  vector<int> indices(v.size()); 
  int count = 0;
  generate(indices.begin(),indices.end(),[&count]()
  { return count++; }); 
  
  // 对indices按照记录的名字域顺序进行排序  
  std::sort(indices.begin(), indices.end(), [&](int a, int b) 
  { return  v[a].name<v[b].name; }); 
  // ...
}

有人认为这“相当简洁”,也有人认为这是一种可能产生危险且晦涩的代码的方式。我的看法是,两者都正确。

  • [&] 是一个“捕捉列表(capture list)”,用于描述将要被lambda函数以引用传参方式使用的局部变量。
  • 如果我们仅想“捕捉”参数v,则可以写为: [&v]。
  • 而如果我们想以传值方式使用参数v,则可以写为:[=v]。
  • 如果什么都不捕捉,则为:[]。
  • 将所有的变量以引用传递方式使用时采用[&], 而相对地,使用[=] 则相应地表示以传值方式使用所有变量。
    (译注:“所有变量”即指lambda表达式在被调用处,所能见到的所有局部变量)

如果某一函数的行为既不通用也不简单,那么我建议采用命名函数对象或者函数。例如,如上示例可重写为:

void f( vector<Record>& v)
{
  vector<int> indices(v.size() ); 
  int count = 0; 
  fill(indices.begin(), indices.end(), [&]() 
  { return ++count; }; 

  struct Cmp_names {
    const vector& vr; 
    Cmp_names(const vector<Record>& r) : vr(r) {} 
    bool operator() (Record& a, Record& b) const { return vr[a] < vr[b]; } 
  }; 

  //对indices按照记录的名字域顺序进行排序 
  std::sort(indices.begin(), indices.end(), Cmp_names(v) ); 
}

(译注:此处采用了函数对象Cmp_names(v)来代替lambda表达式,由于Cmp_names具有以引用传参方式的构造函数,因此Cmp_names(v)相当于使用了”[&v]”的lambda表达式)

对于简单的函数功能,比如记录名称域的比较,采用函数对象就略显冗长,尽管它与lambda表达式生成的代码是一致的。在C++98中,这样的函数对象在被用作模板参数时必须是“非本地”的(译注:即你不能在函数对象中像此处的lambda表达式那样使用被调用处的局部变量),然而在C++中(译注:意指C++0x),这不再是必须的。

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

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

int n = [] (int x, int y) { return x + y; }(5, 4);
cout << n << endl;

参考资料
Lambda表达式 | cpp11新特性详解与应用
Lambda表达式 | C++11 FAQ 中文版
C++11 lambda表达式 - KingsLanding
用作模板参数的局部类型 | C++11 FAQ 中文版

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,590评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,808评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,151评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,779评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,773评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,656评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,022评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,678评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,038评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,756评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,411评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,005评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,973评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,053评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,495评论 2 343

推荐阅读更多精彩内容

  • 简介 概念 Lambda 表达式可以理解为简洁地表示可传递的匿名函数的一种方式:它没有名称,但它有参数列表、函数主...
    刘涤生阅读 3,193评论 5 18
  • 声明:本文翻译自The Java™ Tutorials(官方文档) 简述 匿名类有一个问题,如果匿名类的实现非常简...
    猴子小皮球阅读 4,628评论 0 9
  • C++ lambda表达式与函数对象 lambda表达式是C++11中引入的一项新技术,利用lambda表达式可以...
    小白将阅读 85,130评论 15 118
  • 我望着前面蠕动的人群,身边的孩子来去匆匆,北京的交通太冷,人们都排着队等着取暖。抬着头看着这被雾霾爱着的天空,灰姑...
    西楼鱼阅读 182评论 0 0
  • 2013年10月22日。遥远的梦想,在深秋的路灯下再也耀不出光芒。因为迷失了方向,在那一瞬间天...
    会旅行的小汉子阅读 375评论 0 0