C++11带来的lambda表达式

C++11带来了lambda表达式,可以简化程序的编写,使代码更加清晰。

现在按照步骤来介绍lambda表达式:

1.函数对象

又叫仿函数,如果一个类或者结构体重载了operator()操作符,那么该类产生的对象就是一个函数对象,例如,有这样一个student结构体:

struct Student {
	unsigned ID;
	string name;
	Student(unsigned i, string n) :
			ID(i), name(n) {
	}
};

如果想对studeng使用ID来进行排序,那么可以写这样一个比较器:

struct compareID {
	bool operator ()(const Student& val1, const Student& val2) const {
		return val1.ID < val2.ID;
	}
};

这就是一个函数对象,因为重载了operator()


2.使用bind简化


使用标准库里的sort函数进行排序的话,看看sort函数的原型:

template <class RandomAccessIterator, class Compare>
  void sort ( RandomAccessIterator first, RandomAccessIterator last, Compare comp );

其中的Compare comp就是一个函数对象,既然我们已经有了compareID这个函数对象,就可以使用sort来排序:

int main(int argc, char* argv[]) {

	Student a[] = { Student(2, “John”), Student(0, “Tom”), Student(1, “Lily”) };
	sort(a, a + 3, compareID());

	for(int i=0; i<3; ++i){

		cout<<a[i].ID<<’ ‘<<a[i].name<<endl;
	}

	return 0
}
没有问题,如果又需要对name进行排序,又得写一个函数对象:

struct compareName {
	bool operator ()(const Student& val1, const Student& val2) const {
		return val1.name < val2.name;
	}
};

用这个函数对象替换上边的compareID,就可以完成对name的排序,但显然比较麻烦,因为要自己写比较用的函数对象。可以使用bind来简化:

sort(a, a+3, bind(less<unsigned>(), bind(&Student::ID, _1), bind(&Student::ID, _2)));
sort(a, a+3, bind(less<unsigned>(), bind(&Student::Name, _1), bind(&Student::Name, _2)));

这是一个bind的嵌套使用,内层的bind把一个成员变量转化成一个函数对象,绑定参数1和2,外层的bind使用std提供的less函数对象完成对两个比较参数的函数对象的绑定。

可以参考boost库对bind的解释:

http://www.boost.org/doc/libs/1_49_0/libs/bind/bind.html#with_functions


3.lambda表达式

但是上述用bind来实现还是比较复杂,先看看labbda表达式如何简化之:

sort(a, a+3, [](const Student& val1, const Student& val2){ return val1.ID < val2.ID; });
那么上述的两种比较就可以这样来完成:

int main(int argc, char* argv[]) {
	
	Student a[] = { Student(2, “John”), Student(0, “Tom”), Student(1, “Lily”) };
	sort(a, a + 3,
			[](const Student& val1, const Student& val2) {return val1.ID < val2.ID;});
	for_each(a, a + 3,
			[](const Student& val) {cout<<val.ID<<’ ‘<<val.name<<endl;});
	return 0
}

是不是简化多了?


以下转自:

http://stblog.baidu-tech.com/?p=1053

有了感性的认识后,我们来分析一下Lambda表达式的语法。

我这里无意把C++标准草案中Lambda表达式的有关章节翻译过来(我也不佩这么做)。只是在这里希望以最通俗的方式将它的语法讲解一二。从结构上说,Lambda表达式可以写成如下的形式:

Lambda-introducer lambda-declarator(opt) compound-statement


其中的Lambda-introducer就是刚刚的那个“[]”它是不能省略的。中括号中也可能出现变量。表示将局部变量传入到Lambda表达式中。lambda-declaratoropt是可选择的,包括了表达式的参数列表,返回值信息, mutable声明(以及一些其它信息,这里不做讨论)。而最后的compound-statement则是表达式的主要内容。

还是看一个例子吧:

int n = 10;
[n](int k) mutable -> int { return k + n; };

程序的第二行是一个lambda表达式,lambda里能出现的东西几乎全了(当然,正如我在前文说的,有一些其它信息这里不做讨论,所以没有加入其中)。让我们对里面的东西一一分析:

l[n]Lambda-introducer,而n是一个变量,表明该表达式作用域中的变量n将被传入这个表达式。以本程序为例,传入的值是10Lambda-introducer可以指定变量以值的方式传入,也可以用其它的形式指定其以引用的方式传入。其变型大家就baidu一下吧J

l(int k)表示了参数列表,属于lambda-declarator的一部分。你可以把表达式看成一个仿函数(如上文的)。这里指定了仿函数的参数列表。如果函数的参数列表为空,这一部分可以省略。

lmutable表示仿函数中的变量能否改变。以前文中compareID这个仿函数为例,注意到其中的operator ()const的。如果lambda表达式中引入了这个mutable,则对应的仿函数中operator()的定义将不包含这个const——这意味着仿函数中的变量值(Lambda-introducer传入)可以改变。讨论operator() constoperator()的区别已经超出了本文的范围,想了解的话,看看C++相关教程吧J

l-> int 表示返回类型(这里是int)。如果编译器能从代码中推断出返回类型,或者Lambda表达式的返回类型为void,则该项可省略;

l{ return k+n; }compound-statement:函数体。

通过分析可以看出,这个Lambda表达式相当于一个函数,该函数读入一个intk,将该值加上n返回。根据上述说明,这个表达式可以简写为:

[n](int k){ return k + n; };

Lambda表达式可以存储在std::function<T>  std:: reference_closure<T>类型的变量中。其中的T表示了表达式对应函数的类型。以上述表达式为例,它输入参数为int型变量,输出为int,那么为了保存它,可以写成如下的形式:

function<int(int)> g = [n](int k){ return k + n; };

另一个例子,前文所使用的Lambda表达式:

[](const Student& val1, const Student& val2){ return val1.ID < val2.ID; }

可以存储于function<bool(const Student&, const Student&)>这个类型的变量中。

如果你嫌这么写麻烦,也可以利用C++新标准中另一个新特性:类型推导。即用auto作为变量的类型,让编译器自己推导表达式的类型:

auto g = [n](int k){ return k + n; };

没问题,这样写g还是一个强类型的变量,只不过其类型是由编译器推导的,好处是你不用写太长的变量类型了J


Lambda表达式进阶


作为结尾,我们来看一些C++ Lambda表达式进阶的用法。

Lambda表达式被引入主要是用于函数式编程。有了Lambda表达式,我们也可以做一些函数式编程的东西。比如将一个函数作为返回值的应用:

auto g = [](int n) -> function<void (int)> {
return [n](int k){ cout<<n+k<<’ ‘; };
};

它是一个Lambda表达式,输入一个整型变量n,返回一个函数(lambda表达式),这个函数接收一个intk,并打印出k+ng的使用方法如下:

int a[]={1,2,3,4,5,6,7,8,9,0};
function<void (int)> f = g(2);
for_each(a, a+10, f);

它将输出:3 4 5 6 7 8 9 10 11 2


有一点函数式编程的味道了J

至于其它的东西,比如如下的表达式:

[](){}();

是一个有效的调用。其中[](){}”表示一个Lambda表达式,其输入参数为空,返回void,什么都不干。而最后的()表示调用其求值——虽然什么都不干,但编译能通过,很唬人喔J



好了,就写到这里吧。关于Lambda表达式想说的最后一件事是:它是新标准C++11中定义的。老的编译器不支持(这也是我用VS2010的原因)。想要用它,以及其它新标准带来的好处吗?嘿,你的家伙(指编译器)该升级了



  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值