转载:http://www.cnblogs.com/kedebug/p/3224561.html

lambda 表达式的简单语法如下:[capture] (parameters) -> return value { body }

1、最简单的例子:

#include <iostream>
using namespace std;
int main()
{
auto func = [] () { cout << "Hello world"; };
func();
}

上 面的 lambda 表达式 func 没有传入任何参数,也没有返回值,甚至我们可以对其简写成:auto func = [] { cout << "Hello world"; } 。并且配合 C++11标准加入的 auto 自动类型判断,省去了以前定义函数指针冗杂繁琐的过程,程序看上去如何优雅、简洁。

2、更加深入的示范:

假设我们有一个存放书籍地址的类,需要传入一个“搜索满足条件地址”的函数,并且将类定义成如下模样:

class AddressBook
{
public:
template<typename Func>
std::vector<std::string> findMatchingAddresses (Func func)
{
std::vector<std::string> results;
for ( auto itr = _addresses.begin(), end = _addresses.end(); itr != end; ++itr )
{
if ( func( *itr ) )
{
results.push_back( *itr );
}
}
return results;
}
private:
std::vector<std::string> _addresses;
};

类 AddressBook 封装了 findMatchingAddresses 函数,返回满足我们需要的书目,下面我们看看 lambda 表达式如何实现这一过程:

AddressBook global_address_book;
vector<string> findAddressesFromOrgs ()
{
return global_address_book.findMatchingAddresses(
[] (const string& addr) { return addr.find( ".org" ) != string::npos; }
);
}

上 面函数返回满足地址中带有 ".org" 字样的书籍条目,lambda 表达式虽然没有定义返回类型,但是编译器可以根据我们的 return 语句自动判断返回值是 boolean 类型。我们的 lambda 表达式中 [] 并没有 capture 任何变量,再下面的例子中将展示 [&] :

string name;
cin >> name;
return global_address_book.findMatchingAddresses(
[&] (const string& addr) { return addr.find( name ) != string::npos; }
);

再 次注意到,类 global_address_book 竟然能够访问到我们定义的局部变量 name 字符串,这正是 lambda 表达式的强大之处,[&] 代表 lambda body 中用到的变量都以“reference”的方式使用,还有更多的 capture 用法这里就不再叙述,有兴趣进一步了解的同学可以自行搜索。

3、Lambda 表达式使 STL 更加强大:

传统的情况下,我们会用下面的方式去访问容器里面的数据:

vector<int> v;
v.push_back( 1 );
v.push_back( 2 );
//...
for ( auto itr = v.begin(), end = v.end(); itr != end; itr++ )
{
cout << *itr;
}

但是当我们有了 Lambda 之后,利用 STL 里面的 for_each ,将会变成下面的代码:

vector<int> v;
v.push_back( 1 );
v.push_back( 2 );
//...
for_each( v.begin(), v.end(), [] (int val)
{
cout << val;
});

你可能会想,上面的 for_each 循环,会不会使我们的程序有性能上的损耗?答案是否定的:for_each 的效率和迭代的效率是一致的,甚至加上 Lambda 之后,for_each 会利用 "loop unrolling" 机制使程序运行的更快。

Lambda 的引入给我们带来了一种全新的编程体验,它可以让我们把 "function" 当做是 "data" 一样传递,并且使我们从繁琐的语法中解放出来,更加关注于 "算法" 本身。我们也称 Lambda 为 Closure(闭包),顾名思义,这使我们的函数变得更加私有,所以限制了别人的访问,同时我们也可以更加方便的编程。

4、Lambda 与 资源管理:

前面在我的 「理解智能指针」一文中提到,智能指针可以利用 C++ 的 RAII(Resource acquisition is initialization) 特性,在类型(class)的析构函数时来完成自动释放指针所指向对象的目的。同样,在 Lambda 中,又把 RAII 这一特性体现的淋漓尽致:

class ScopeGuard
{
public:
explicit ScopeGuard(std::function<void()> onExitScope)
: onExitScope_(onExitScope)
{ }
~ScopeGuard()
{
onExitScope_();
}
private:
std::function<void()> onExitScope_;
private: // noncopyable
ScopeGuard(ScopeGuard const&);
ScopeGuard& operator=(ScopeGuard const&);
};
int main() {
HANDLE h = CreateFile(...);
ScopeGuard onExit([&] { CloseHandle(h); });
...
return 0;
}

看到上面的代码,我已经被 C++11 引入 Lambda 之后所带来的强大功能所折服了。我们不必担心何时去释放资源,并且连释放资源的方式「如 CloseHandle(h)」也与我们的代码紧密的融合在了一起,这将是十分美妙的一件事情。

5、Lambda 到底是什么类型:

auto func = [] () { cout << "hello world"; };
std::function<void ()> func = [] () { cout << "hello world"; }; auto func = [] (int val) { cout << val; return false; };
std::function<bool (int)> func = [] (int val) { cout << val; return false; };

上面的上下 2 行代码效果是等效的,看到这里是否有种似曾相识的感觉?那 Lambda 和 我们定义的函数指针有什么区别呢:

typedef int (*func)();
func f = [] () -> int { return 2; };
f();

没错,这段代码是可以正常运行的,因为 Lambda 表达式中并没有 capture 任何本地变量,因此会被编译成普通的函数指针。最后采用 coolshell 里面 Lambda 的 2 点总结: 1)可以定义匿名函数,2)编译器会把其转成函数对象。

C++ 11 lambda的更多相关文章

  1. C++11 lambda 表达式

    C++11 新增了很多特性,lambda 表达式是其中之一,如果你想了解的 C++11 完整特性,建议去这里,这里,这里,还有这里看看.本文作为 5 月的最后一篇博客,将介绍 C++11 的 lamb ...

  2. C++11 lambda 表达式解析

    C++11 新增了很多特性,lambda 表达式是其中之一,如果你想了解的 C++11 完整特性,建议去这里,这里,这里,还有这里看看.本文作为 5 月的最后一篇博客,将介绍 C++11 的 lamb ...

  3. C++ 11 Lambda表达式、auto、function、bind、final、override

    接触了cocos2dx 3.0,就必须得看C++ 11了.有分享过帖子:[转帖]漫话C++0x(四) —- function, bind和lambda.其实最后的Lambda没太怎么看懂. 看不懂没关 ...

  4. c++11 lambda(了解)

    this->send_change_equip = ([this](ChangeEquipPT channge) { send_cmd(s2c_change_equip, &channg ...

  5. C++11 Lambda表达式简单解析

    C++11 新增了非常多特性,lambda 表达式是当中之中的一个.假设你想了解的 C++11 完整特性, 建议去http://www.open-std.org/看看新标准! 非常多语言都提供了 la ...

  6. 详解 C++11 lambda表达式

    详解 C++11 lambda表达式   lambda表达式是函数式编程的基础.咱对于函数式编程也没有足够的理解,因此这里不敢胡言乱语,有兴趣的可以自己查找相关资料看下.这里只是介绍C++11中的la ...

  7. C++11 lambda的理解

    C++11 的 lambda 表达式规范如下: [ capture ] ( params ) mutable exception attribute -> ret { body } (1) [ ...

  8. C++11—lambda函数

    [1]lambda表达式语法定义 lambda表达式的语法定义如下: [capture] (parameters) mutable ->return-type {statement}; (1) ...

  9. C++11 lambda表达式学习

    lambda表达式是函数式编程的基础.咱对于函数式编程也没有足够的理解,因此这里不敢胡言乱语,有兴趣的可以自己查找相关资料看下.这里只是介绍C++11中的lambda表达式自己的认识.这里有参考文档h ...

随机推荐

  1. 如何让老Mac机支持USB安装Windows

    一些老Mac机的用户想装Windows,却发现自己的系统上的Boot Camp Assistant(以下简称BCA)没有USB安装Windows的选项. 下面以我的MacBook Pro (13-in ...

  2. LeetCode——Letter Combinations of a Phone Number

    Given a digit string, return all possible letter combinations that the number could represent. A map ...

  3. php : 基础(3)

    运算符 算术运算符 基础: 符号有:+   -   *   /   % 说明: 他们都是针对数字进行的运算: 如果他们的两边有不是数字的数据,就会(自动)转换为数字: 其中取余运算(取模运算)%,它只 ...

  4. JAVA 1.3 (原生数据类型 Primitive Data Type)续

    1. 原生数据类型一共有4类8种 >> 整数类型 int表示一个int代表32位 2^32(-2147483648 - 2147483647) >> 字符类型 byte 表示一 ...

  5. Linux下的系统调用

    张雨梅   原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-10000 1.linux的的用户态与内核 ...

  6. idea中配置eslint 静态代码检查

    配置: 1,安装依赖 sudo tnpm install eslint -g sudo tnpm install eslint-plugin-import -g sudo tnpm install e ...

  7. Redis中的客户端redis-cli 命令总结

    1.连接操作相关的命令quit:关闭连接(connection)auth:简单密码认证 2.对value操作的命令exists(key):确认一个key是否存在del(key):删除一个keytype ...

  8. redhat samba匿名登录服务器搭建

    smb服务器只需要yum install samba 安装起,并修改配置文件就可以匿名使用了.   smb配置文件,这里允许匿名登录.红色部分代表我共享出来文件夹参数code [root@localh ...

  9. 原创:Equinox OSGi应用嵌入Jersey框架搭建REST服务

    一.环境 eclipse版本:eclipse-luna 4.4 jre版本:1.8 二.Equinox OSGi应用嵌入Jersey框架搭建REST服务 1.新建插件工程HelloWebOSGI a. ...

  10. Python之路 day2 文件基础操作

    #!/usr/bin/env python # -*- coding:utf-8 -*- #Author:ersa ''' #f,文件句柄;模式 a : append 追加文件内容 f = open( ...