本篇文章由:http://www.sollyu.com/c11-new-lambda-function/

文章列表

本文章为系列文章

【C++11】新特性——auto的使用 http://www.sollyu.com/c11-new-features-auto/

【C++11】新特性——Lambda函数 http://www.sollyu.com/c11-new-lambda-function/

说明

在标准 C++,特别是当使用 C++ 标准程序库算法函数诸如 sortfind,用户经常希望能够在算法函数调用的附近定义一个临时的述部函数(又称谓词函数,predicate function)。

由于语言本身允许在函数内部定义类型,可以考虑使用函数对象,然而这通常既麻烦又冗赘,也阻碍了代码的流程。此外,标准 C++ 不允许定义于函数内部的类型被用于模板,所以前述的作法是不可行的。

C++11 对 lambda 的支持可以解决上述问题。

一个 lambda 函数可以用如下的方式定义:

[](int x, int y) { return x + y; }

指定返回类型

这个不具名函数的回返类型是 decltype(x+y)。只有在 lambda 函数符合"return expression"的形式下,它的回返类型才能被忽略。在前述的情况下,lambda 函数仅能为一个述句。

在一个更为复杂的例子中,回返类型可以被明确的指定如下:

[](int x, int y) -> int { int z = x + y; return z + x; }

本例中,一个临时的参数 z 被创建用来存储中间结果。如同一般的函数,z 的值不会保留到下一次该不具名函数再次被调用时。

如果 lambda 函数没有传回值(例如 void ),其回返类型可被完全忽略。

定义在与 lambda 函数相同作用域的参数参考也可以被使用。这种的参数集合一般被称作 closure (闭包)。

样式说明

[]          // 沒有定義任何變數。使用未定義變數會導致錯誤。
[x, &y] // x 以傳值方式傳入(預設),y 以傳參考方式傳入。
[&] // 任何被使用到的外部變數皆隱式地以參考方式加以引用。
[=] // 任何被使用到的外部變數皆隱式地以傳值方式加以引用。
[&, x] // x 顯示地以傳值方式加以引用。其餘變數以參考方式加以引用。
[=, &z] // z 顯示地以參考方式加以引用。其餘變數以傳值方式加以引用。

closure 被定义与使用如下:

std::vector<int> someList;
int total = 0;
std::for_each(someList.begin(), someList.end(), [&total](int x) {
total += x;
});
std::cout << total;

上例可计算 someList 元素的总和并将其印出。

参数 total 是 lambda 函数 closure 的一部分,同时它以引用方式被传递入谓词函数, 因此它的值可被 lambda 函数改变。

若不使用引用的符号&,则代表参数以传值的方式传入 lambda 函数。

让用户可以用这种表示法明确区分参数传递的方法:传值,或是传参考

由于 lambda 函数可以不在被声明的地方就地使用(如置入 std::function 对象中);

这种情况下,若参数是以传参考的方式链接到 closure 中,是无意义甚至是危险的行为。

若 lambda 函数只在定义的作用域使用, 则可以用 [&] 声明 lambda 函数, 代表所有引用到 stack 中的参数,都是以参考的方式传入, 不必一一显式指明:

std::vector<int> someList;
int total = 0;
std::for_each(someList.begin(), someList.end(), [&](int x) {
total += x;
});

参数传入 lambda 函数的方式可能随实做有所变化,一般期望的方法是 lambda 函数能保留其作用域函数的 stack 指针,借此访问区域参数。

若使用 [=] 而非 [&],则代表所有的参考的参数都是传值使用。

对于不同的参数,传值或传参考可以混和使用。 比方说,用户可以让所有的参数都以传参考的方式使用,但带有一个传值使用的参数:

int total = 0;
int value = 5;
[&, value](int x) { total += (x * value); };

total 是传参考的方式传入 lambda 函数,而 value 则是传值。

若一个 lambda 函数被定义于某类型的成员函数中,会被当作该类型的 friend。像这样的 lambda 函数可以使用该类型对象的参考,并且能够访问其内部的成员。

[](SomeType *typePtr) { typePtr->SomePrivateMemberFunction(); };

这只有当该 lambda 函数创建的作用域是在 SomeType 的成员函数内部时才能运作。

在成员函数中指涉对象的 this 指针,必须要显式的传入 lambda 函数, 否则成员函数中的 lambda 函数无法使用任何该对象的参数或函数。

[this]() { this->SomePrivateMemberFunction(); };

若是 lambda 函数使用 [&] 或是 [=] 的形式,this在 lambda 函数即为可见。

lambda 函数是编译器从属类型的函数对象; 这种类型名称只有编译器自己能够使用。如果用户希望将 lambda 函数作为参数传入,该类型必须是模版类型,或是必须创建一个 std::function 去获取 lambda 的值。使用 auto 关键字让我们能够存储 lambda 函数:

auto myLambdaFunc = [this]() { this->SomePrivateMemberFunction(); };
auto myOnheapLambdaFunc = new auto([=] { /*...*/ });

但是,如果 lambda 函数是以参考的方式获取到它所有的 closure 参数,或者是没有 closure 参数,那么所产生的函数对象会被给予一个特殊的类型:std::reference_closure<R(P)>,其中 R(P) 是包含回返类型的函数签名。

比起由 std::function 获取而来,这会是lambda函数更有效率的代表:

std::reference_closure<void()> myLambdaFunc = [this]() { this->SomePrivateMemberFunction(); };
myLambdaFunc();

【C++11】新特性——Lambda函数的更多相关文章

  1. 【转】C++11新特性——lambda表达式

    C++11的一大亮点就是引入了Lambda表达式.利用Lambda表达式,可以方便的定义和创建匿名函数.对于C++这门语言来说来说,“Lambda表达式”或“匿名函数”这些概念听起来好像很深奥,但很多 ...

  2. C++11新特性 lambda表达式

    C++11 添加了了一个名为lambda表达式的功能,可以用于添加匿名函数 语法: [capture_block](parameter) mutable exception_specification ...

  3. C++11新特性之八——函数对象function

    详细请看<C++ Primer plus>(第六版中文版) http://www.cnblogs.com/lvpengms/archive/2011/02/21/1960078.html ...

  4. C++ 11 新特性:函数声明auto

    1.概览 1.1 函数名中的箭头,用来表明函数的return type,其使用在函数的返回类型需要通过模板参数进行推导,使用在decltype()和declval()不方便的场景 2.正文 c++ 中 ...

  5. C++11新特性之一——Lambda表达式

    C++11新特性总结可以参考:http://www.cnblogs.com/pzhfei/archive/2013/03/02/CPP_new_feature.html#section_6.8 C++ ...

  6. C++ 11学习和掌握 ——《深入理解C++ 11:C++11新特性解析和应用》读书笔记(一)

    因为偶然的机会,在图书馆看到<深入理解C++ 11:C++11新特性解析和应用>这本书,大致扫下,受益匪浅,就果断借出来,对于其中的部分内容进行详读并亲自编程测试相关代码,也就有了整理写出 ...

  7. C++11新特性总结 (二)

    1. 范围for语句 C++11 引入了一种更为简单的for语句,这种for语句可以很方便的遍历容器或其他序列的所有元素 vector<int> vec = {1,2,3,4,5,6}; ...

  8. C++ 11 新特性

    C++11新特性:          1.auto          2.nullptr          3.for          4.lambda表达式          5.override ...

  9. [转载] C++11新特性

    C++11标准发布已有一段时间了, 维基百科上有对C++11新标准的变化和C++11新特性介绍的文章. 我是一名C++程序员,非常想了解一下C++11. 英文版的维基百科看起来非常费劲,而中文版维基百 ...

随机推荐

  1. HW3.23

    import java.util.Scanner; public class Solution { public static void main(String[] args) { Scanner i ...

  2. SQL SERVER 导入EXCEL的存储过程

    1.先在查询分析器里执行 exec sp_configure "show advanced options",1 reconfigure exec sp_configure &qu ...

  3. hdu1839之二分+邻接表+Dijkstra+队列优化

    Delay Constrained Maximum Capacity Path Time Limit: 10000/10000 MS (Java/Others)    Memory Limit: 65 ...

  4. 383. Container With Most Water

    最后更新 一刷. 双指针夹逼. 容器的高度受限于较小的边,夹的时候底在变小,所以移动较大的边没有意义,最终高度还是小的那边:只能尝试移动小的那个边. public class Solution { p ...

  5. Java空字符串与null的区别和判断字符串是否为空的方法

    Java空字符串与null的区别: 1.类型null表示的是一个对象的值,而并不是一个字符串.例如声明一个对象的引用,String a = null ;""表示的是一个空字符串,也 ...

  6. android 处理图片之--bitmap处理

    -2.从资源中获得bitmap Resources res=getResources(); Bitmap bmp=BitmapFactory.decodeResource(res, R.drawabl ...

  7. CAS分析——Core

    国内私募机构九鼎控股打造APP,来就送 20元现金领取地址:http://jdb.jiudingcapital.com/phone.html内部邀请码:C8E245J (不写邀请码,没有现金送)国内私 ...

  8. CSS3:clip-path具体解释

    我的一个学生,Heather Banks,想要实现他在Squarespace看到的一个效果: 依据她的以往经验,这个站点的HTML和CSS是全然在她的能力范围以内,于是我帮助她完毕了这个效果.显示na ...

  9. Linux内核:关于中断你须要知道的

    1.中断处理程序与其它内核函数真正的差别在于,中断处理程序是被内核调用来对应中断的,而它们执行于中断上下文(原子上下文)中,在该上下文中执行的代码不可堵塞. 中断就是由硬件打断操作系统. 2.异常与中 ...

  10. careercup-递归和动态规划 9.2

    9.2 设想有个机器人坐在X*Y网格的左上角,只能向右.向下移动.机器人从(0,0)到(X,Y)有多少种走法? 进阶: 假设有些点为“禁区”,机器人不能踏足.设计一种算法,找到一条路径,让机器人从左上 ...