(原创)C++11改进我们的程序之简化我们的程序(六)
这次要讲的内容是:c++11中的lamda表达式。
lamda表达式是我最喜欢的一个c++11特性之一,在我的代码中随处可见它的身影,其实在c#3.5中就引入了lamda,java中至今还没引入,要等明年的java8中才有lamda表达式,lamda来源于函数式编程的概念,也是现代编程语言的一个特点。c++11这次终于把lamda加进来了。也许有人要问,lamda有什么好处,为什么要加到c++中来?lamda表达式有这些优点:
- 声明式编程风格:就地匿名定义你的目标函数或函数对象,不需要额外的写一个命名函数或者函数对象。以更直接的方式去写程序,好的可读性和可维护性。
- 简洁:不需要额外再写一个函数或者函数对象,避免了代码膨胀和功能分散,让开发者更加集中精力在手边的问题,同时也获取了更高的生产率。
- 在需要的时间和地点实现谓词,使我们的程序更灵活。
lamda表达式定义了一个匿名函数,并且可以捕获一定范围内的变量。lamda表达式的语法形式:
[ capture ] ( params ) -> ret { body }
如果没有返回值也没有参数,可以这样简写:
[](){ body }或者[]{ body }
[] (int x) -> { return x; }
auto fun = [](){cout<<"test"}
fun();
lamda表达式可以截取一定范围内的变量:
[] 不截取任何变量
[&} 截取外部作用域中所有变量,并作为引用在函数体中使用
[=] 截取外部作用域中所有变量,并拷贝一份在函数体中使用
[=, &foo] 截取外部作用域中所有变量,并拷贝一份在函数体中使用,但是对foo变量使用引用
[bar] 截取bar变量并且拷贝一份在函数体重使用,同时不截取其他变量
[this] 截取当前类中的this指针。如果已经使用了&或者=就默认添加此选项。截取this的目的是可以在lamda中使用当前类的成员函数和成员变量。
声明式编程风格,简洁的代码
就地定义匿名函数,不再需要定义函数对象,大大简化了标准库算法的调用。比如c++11之前我们要调用for_each函数将vector中偶数打印出来,可能要这样写:
struct CountEven
{
CountEven(int& count) : m_count(count)
{
} void operator()(int val)
{
if(val/==)
{
m_count++;
}
} private:
int m_count;
}; int evenCount=;
for_each(v.begin(),v.end(),CountEven(evenCount));
cout<<"偶数有 "<<evenCount<<" 个"<<endl;
用lamda表达式写:
for_each(v.begin(),v.end(), [&evenCount](const int& val)
{
if(val/==)
{
evenCount++;
}
});
不再需要定义函数对象,而且更简洁明了,可读性和维护性更好,开发效率也更高。
在需要的时间和地点实现谓词,使我们的程序更灵活。
上一篇博文中的那个计算集合中大于5小于10的函数用Lamda更简洁,之前用bind的写法:
//查找大于10的元素的个数
int count = count_if(coll.begin(), coll.end(), bind1st(less<int>(), ));
//查找小于10的元素的个数
int count = count_if(coll.begin(), coll.end(), bind2nd(less<int>(), )); //查找大于5小于10的元素的个数
auto f = bind(std::logical_and<bool>(), bind(std::greater<int>(),_1,), bind(std::less_equal<int>(),_1,));
int count = count_if(coll.begin(), coll.end(), f);
用lamda的写法:
//查找大于10的元素的个数
int count = count_if(coll.begin(), coll.end(), [](int x){return x>;});
//查找小于10的元素的个数
int count = count_if(coll.begin(), coll.end(), [](int x){return x<;});
//查找大于5小于10的元素的个数
int count = count_if(coll.begin(), coll.end(), [](int x){return x>&&x<;});
孰优孰劣,一眼便知,这就是生产力啊。
lamda捕获参数
stuct A
{
A():m_cout(){}
bool Add(int x, int y)
{
return x>y;
} void TestLamda()
{
vector<int> v = {,,,};
sort(v.begin(), v.end(), [this](int x, int y){return Add(x,y);}); //调用成员函数,需要捕获this才可以 int z = ;
sort(v.begin(), v.end(), [this,z](int x, int y) //z按值捕获
{
m_count = ; //给成员变量赋值
return Add(x,y);
}); //调用成员函数,需要捕获this才可以 sort(v.begin(), v.end(), [this,&z](int x, int y) //z按引用捕获
{
z = count+; //给z赋值
return Add(x,y);
}); //以引用方式传递作用域内所有可见的局部变量(包括this)
for_each(v.begin(), v.end(), [=](int x){cout<<z+x<<endl;}); //以引用方式传递作用域内所有可见的局部变量(包括this)
for_each(v.begin(), v.end(), [&](int x){z++; cout<<z+x<<endl;}); //部分变量按引用传递
for_each(v.begin(), v.end(), [this, &z](int x){z++; cout<<z+x<<endl;});
} int m_cout;
};
lamda能捕获变量很有用,一些外面的参数可以根据需要按值或者引用传入闭包。我甚至觉得lamda表达式几乎可以取代function, 可以通过捕获对象并调用对象的成员函数的方式取代bind成员函数的方式。例如:
用bind和function的写法:
A a;
auto f = std::bind(&A::Add, &a, std::placehoders::_1,std::placehoders::_2);
int x = , y=;
auto ret = f(x, y);
用lamda的写法:
auto f = [&a](int x, int y){return a.Add(x, y);};
auto ret = f(x, y);
效果是一样的,代码还更简洁了。不过不能完全替代function的原因是lamda表达式不能作为成员变量,还有有些标准库的和boost的方法不支持lamda,还需要function出场。
c++11引入函数式编程的概念中的lamda,让我们的代码更简洁,更灵活,也更强大,并提高了开发效率,提高了可维护性。再次说一声lamada真是个好东西!
c++11 boost技术交流群:296561497,欢迎大家来交流技术。
(原创)C++11改进我们的程序之简化我们的程序(六)的更多相关文章
- (原创)C++11改进我们的程序之简化我们的程序(八)
本次要讲的是如何通过泛型函数来简化我们的程序. 泛型函数除了之前介绍的一些优点外还有两个重要的优点 1.消除重复逻辑,提高程序的内聚性和健壮性 泛型函数在某种程度上用来弥补泛型类型的不足.通过泛型类型 ...
- (原创)C++11改进我们的程序之简化我们的程序(二)
这次要讲的是:C++11如何通过组合函数来简化我们的程序.关于组合函数,大家可能对这个概念有点陌生.组合函数是将N个一元函数组成一种更复杂的函数,每个函数的返回值作为参数传给下一个函数,直到传到最后一 ...
- C++11改进我们的程序之简化我们的程序1
C++11改进我们的程序之简化我们的程序(一) C++11在很多方面可以简化我们的程序开发,我会在“简化我们的程序”这一系列的博文中一一讲到,敬请关注.这次要讲的是:C++11如何通过获取函数模板的返 ...
- (原创)C++11改进我们的程序之简化我们的程序(四)
这次要讲的是:c++11统一初始化.统一begin()/end()和for-loop循环如何简化我们的程序 初始化列表 c++11之前有各种各样的初始化语法,有时候初始化的时候还挺麻烦,比较典型的如v ...
- (原创)C++11改进我们的程序之简化我们的程序(三)
这次要讲的是:C++11如何通过auto.decltype和返回值后置来简化我们的程序. auto和c#中的var类似,都是在初始化时自动推断出数据类型.当某个变量的返回值难于书写时,或者不太确定返回 ...
- (原创)C++11改进我们的程序之简化我们的程序(一)
C++11在很多方面可以简化我们的程序开发,我会在“简化我们的程序”这一系列的博文中一一讲到,敬请关注.这次要讲的是:C++11如何通过获取函数模板的返回值类型来简化我们的程序.在谈到简化之前,我们先 ...
- (原创)c++11改进我们的模式之改进代理模式,实现通用的AOP框架
c++11 boost技术交流群:296561497,欢迎大家来交流技术. 本次要讲的时候如何改进代理模式,具体来说是动态代理模式,动态代理模式一般实现AOP框架,不懂AOP的童鞋看这里.我前面的博文 ...
- (原创)c++11改进我们的模式之改进命令模式
模式虽然精妙,却难完美,比如观察者模式中观察者生命周期的问题:比如访问者模式中循环依赖的问题等等:其它很多模式也存在这样那样的一些不足之处,如使用场景受限.实现复杂.不够简洁.不够通用等.但我觉得不足 ...
- (原创)c++11改进我们的模式之改进访问者模式
本次讲c++11改进我们的模式之改进访问者模式 访问者模式是GOF23个设计模式中比较复杂的模式之一,但是它的功能也很强大,非常适合稳定的继承层次中对象的访问,可以在不修改被访问对象的情况下,动态添加 ...
- (原创)C++11改进我们的程序之简化我们的程序(七)
这次要讲的内容是:c++11中的tuple(元组).tuple看似简单,其实它是简约而不简单,可以说它是c++11中一个既简单又复杂的东东,关于它简单的一面是它很容易使用,复杂的一面是它内部隐藏了太多 ...
随机推荐
- DirectX中文手册
目 录 第一章 DirectX基础(初级篇) 第一节 什么是DirectX 一.什么是DirectX ? 二.DirectX的组成部分 三.关于DirectDraw 四.为什么要使用DirectD ...
- Android 百度鹰眼轨迹SDK(v2.1.6)
闲聊 看过<鹰眼追击>这部电影的读者一定对"鹰眼"这台巨无霸计算机印象深刻,如今我们能够实现自己的鹰眼. 效果图 本篇为百度地图SDK第三篇博文 第一篇实现:Andro ...
- 设置visual studio的小技巧
设置 Visual Studio 方法 1.设置关闭快捷键 Ctrl + W:关闭当前文档窗口 Ctrl + Q:关闭所有文档窗口 设置方法:工具-->选项-->键盘:在显示命令包含中输入 ...
- hduoj1073--Online Judge
做道题,并没有太多的技巧,关键在与对Accepted,presented error 和wa的判断,第一步如果两者完全一样,那么很定是AC了 ,否则如果去掉多余换行,空格,制表后还有不同说明是数据 不 ...
- node下使用jquery
node使用jquery的两种方式 在node下,使用jquery有两种方法: 使用jsdom模拟一个window对象 使用cheerio,cheerio只实现了jquery的dom部分功能,相当于j ...
- hihocoder216周:贪心或二分
题目链接 有N条线段,要切K刀,使得最长的线段尽量短.在最佳切割的条件下,切完之后最长的那根绳子是多长. 方法一:贪心 每次切的那一刀必然是最长的那条线段,用优先队列,每次往最长的那条线段上切一刀 方 ...
- 【转】GDB中应该知道的几个调试方法
文章来源:http://coolshell.cn/articles/3643.html GDB中应该知道的几个调试方法 2011年02月10日 陈皓 评论 40 条评论 70,776 人阅读 七.八 ...
- Percona XtraBackup介绍
Percona XtraBackup开源的.免费的mysql热备软件,可以执行无阻塞备份InnoDB和XtraDB数据库. Percona XtraBackup有以下优点: ·备份快速.可靠 ·备份期 ...
- Transparent Huge Pages
在RHEL6中,透明大页功能是默认开启的. 开启该选项后,内核会尽可能地尝试分配大页,如果mmap区域是2mb,那么每个linux进程都会分配到2mb大小的页.如果大页不够用了(比如物理内存不够了), ...
- Sails入门指南
1.全局观:sails理念,框架结构 2.试用sails的scaffolding工具,创建model,创建controller, 3.启动server,试用blueprint, 4.进阶: 4.0 数 ...