维基百科上面对于 lambda 的引入是如下描述的:

在标准 C++,特别是当使用 C++ 标准程序库算法函数诸如 sort 和 find。用户经常希望能够在算法函数调用的附近定义一个临时的述部函数(又称谓词函数,predicate function)。由于语言本身允许在函数内部定义类型,可以考虑使用函数对象,然而这通常既麻烦又冗赘,也阻碍了代码的流程。此外,标准 C++ 不允许定义于函数内部的类型被用于模板,所以前述的作法是不可行的。C++11 对lambda的支持可以解决上述问题。

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)编译器会把其转成函数对象。

6、 使用 Lambda 进行代码委托(调用):

「参考资料」

http://zh.wikipedia.org/wiki/C%2B%2B11

http://mindhacks.cn/2012/08/27/modern-cpp-practices/

http://www.cprogramming.com/c++11/c++11-lambda-closures.html

http://coolshell.cn/articles/5265.html

「C++11」Lambda 表达式的更多相关文章

  1. C++11之lambda表达式

    lambda表达式源于函数式编程的概念,它可以就地匿名定义目标函数或函数对象,不需要额外写一个命名函数或者函数对象.lambda表达式的类型在C++11中被称为"闭包类型",也可以 ...

  2. C++11 里lambda表达式的学习

    最近看到很多关于C++11的文档,有些是我不怎么用到,所以就略过去了,但是lambda表达式还是比较常用的,其实最开始学习python的时候就觉得lambda这个比较高级,为什么C++这么弱.果然C+ ...

  3. 【C++11】 lambda表达式

    i.e.int x = 10;int y = 20;int z = [&]{ x = x * x; y = y * y; return x + y;}(); 上面z后面以[]开头的为一个lam ...

  4. C++11之lambda表达式应用

    应用 foreach语句中 #include <time.h> #include <algorithm> using namespace std; void func(int ...

  5. C++11之lambda表达式解析

    什么是Lanmbda? 简短函数,就地书写.常用于向函数(算法)传递函数参数. 语法 Lambda 表达式,[capture](paras)mutable->return type{statem ...

  6. c++11:lambda表达式的使用

    lambda表达式的一般形式: [capture list] (parameter list) -> return type{function body}; 其中,capture list (捕 ...

  7. STL - C++ 11的Lambda表达式(上)

    Lambda始自C++ 11,是一种在表达式或语句内指定函数行为的定义式. 你可以定义函数行为作为对象,以inline实参的形式传给算法作为predicate(判断式). eg: std:transf ...

  8. STL - C++ 11的Lambda表达式(下)

    关于lambda的基础知识,请参考上一篇的地址如下: http://www.cnblogs.com/davidgu/p/4825625.html 我们再举个STL使用Lambda来进行排序的例子,如下 ...

  9. 「10.11」chess(DP,组合数学)·array(单调栈)·ants(莫队,并茶几)

    菜鸡wwb因为想不出口胡题所以来写题解了 A. chess 昨天晚上考试,有点困 开考先花五分钟扫了一边题,好开始肝$T1$ 看了一眼$m$的范围很大,第一反应矩阵快速幂?? $n$很小,那么可以打$ ...

随机推荐

  1. pureftp在centos下与MySQL搭配使用

    概述 pure-ftpd是linux下的一个ftp服务端,据说安全性较高.我在centos6下用yum安装pure-ftpd,并配置了通过MySQL进行用户的增删改查,以及对应到apache的web目 ...

  2. Git,non-fast-forward

    当把coding好的code,push到Git时会出现这个错误:master[rejected  non-fast-forward] 问题(Non-fast-forward)的出现原因在于:git仓库 ...

  3. sass接触

    第一句话就是棒棒的,我爱上了. 看了真阿当的文章:<2016年前端技术观察> http://weibo.com/ttarticle/p/show?id=230940405256054051 ...

  4. MySQL的InnoDB索引原理详解

    摘要 本篇介绍下Mysql的InnoDB索引相关知识,从各种树到索引原理到存储的细节. InnoDB是Mysql的默认存储引擎(Mysql5.5.5之前是MyISAM,文档).本着高效学习的目的,本篇 ...

  5. Linux服务器配置多台虚拟主机

    2016年11月4日15:59:12 LAMP环境 参考:http://blog.itblood.com/nginx-same-ip-multi-domain-configuration.html 在 ...

  6. SecureCRT上传和下载文件

    SecureCRT上传和下载文件(下载默认目录) SecureCR 下的文件传输协议有ASCII .Xmodem .Ymodem .Zmodem ASCII:这是最快的传输协议,但只能传送文本文件. ...

  7. 如何提高账户密码存储的安全性——PasswordSalt的使用

    使用 Salt + Hash 将密码加密后再存储进数据库 如果你需要保存密码(比如网站用户的密码),你要考虑如何保护这些密码数据,象下面那样直接将密码写入数据库中是极不安全的,因为任何可以打开数据库的 ...

  8. apache配置 php中没有php5apache2_4.dll

    apache配置 php中没有php5apache2_4.dll 今天,在win7系统下安装Apache+PHP+MySQL时,终于体会到了版本多也不一定是好事,各种不兼容,主要是因为动态包的多少问题 ...

  9. JavaScript中的this陷阱的最全收集

    JavaScript来自一门健全的语言,所以你可能觉得JavaScript中的this和其他面向对象的语言如java的this一样,是指存储在实例属性中的值.事实并非如此,在JavaScript中,最 ...

  10. KMP学习之旅

    说起kmp就要从字符串的匹配说起,下面我们谈谈字符串的匹配 给定一个原字符串:bababababababababb,再给定一个模式串:bababb,求模式串是否在源字符串中出现 最简单的方法就是遍历源 ...