c++ lambda表达式详解

int32位 posted @ Nov 07, 2013 08:49:49 PM in c/cpp , 6146 阅读
转载请注明:http://krystism.is-programmer.com/若有错误,请多多指正,谢谢!

lambda表达式是c++11标准新加特性,学过python的一定不会陌生了,或者类似javascript的闭包。cppreference中的定义是:Constructs a closure: an unnamed function object capable of capturing variables in scope. 简单地说就是定义一个临时局部匿名函数。语法为:

[ capture ] ( params ) mutable exception attribute -> ret { body }

其中capture为定义外部变量是否可见(捕获),(这里的外部变量是指与定义这个lambda处于同一个作用域的变量)。

若为空,则表示不捕获所有外部变量,即所有外部变量均不可访问,= 表示所有外部变量均以值的形式捕获,在body中访问外部变量时,访问的是外部变量的一个副本,类似函数的值传递,因此在body中对外部变量的修改均不影响外部变量原来的值。& 表示以引用的形式捕获,后面加上需要捕获的变量名,没有变量名,则表示以引用形式捕获所有变量,类似函数的引用传递,body操作的是外部变量的引用,因此body中修改外部变量的值会影响原来的值。例如:[ ]表示不捕获任何外部变量, [a, b]以值的形式捕获a,b, [=]以值的形式捕获所有外部变量,[&a, b]a以引用的形式捕获,而b以值的形式捕获,[&, a],除了a以值的形似捕获,其他均以引用的形式捕获,[this]以值的形式捕获this指针!

params就是函数的形参,和普通函数类似,不过若没有形参,这个部分可以省略。

mutalbe表示运行body修改通过拷贝捕获的参数,exception声明可能抛出的异常,attribute 修饰符,参考:http://en.cppreference.com/w/cpp/language/attributes ->ret ret表示返回类型,如果能够根据返回语句自动推导,则可以省略,body即函数体。

注意:除了capture和body是必需的,其他均可以省略,即

int main(int argc, char **argv)
{
	[]{}();
	return 0;
}

定义了一个空lambda表达式,并执行(实际上它什么都没有做)。

int main(int argc, char **argv)
{
	int i = 0;
	[]{cout << i << endl;}(); /* 'i' is not captured */ 
	return 0;
}

声明这段代码不能编译通过,因为[ ] 没有捕获任何外部变量,因此i是不可见的,lambda不能访问i。

int main(int argc, char **argv)
{
	int i = 0;
	cout << i << endl;
	[=]()mutable{cout << ++i << endl;}();
	cout << i << endl;
	return 0;
}

上面的代码输出为0, 1, 0,注意mutable是必需的,因为body中修改了捕获的i,由于i是以值传递的,因此并没有修改i原来的值,而是i的一个副本。

int main(int argc, char **argv)
{
	int i = 0;
	cout << i << endl;
	[&](){cout << ++i << endl;}();
	cout << i << endl;
	return 0;
}

上面代码输出0, 1, 1,因为i是以引用传递的,而body中修改了i的值。

lambda表达式有什么用呢? lambda的作用就是创建一个临时匿名函数,想想有STL算法中很多需要传递谓词函数,比如count_if。假如我有一个字符串容器,我需要统计长度大于3的个数,则可以这样:

int main(int argc, char **argv)
{
	vector<string> s = {"1", "12", "123", "1234", "12345", "123456", "1234567"};
	cout << count_if(begin(s), end(s), [](string s){return s.size() > 3;});
	return 0;
}

这样就不必要再声明一个函数了,代码比较简洁。

还有一个问题就是,我可能需要统计字符串长度大于4,或者5,或者6,显然不能通过传递一个形参来实现,因为谓词函数限定只能传递一个形参,这里我们传递的是string,而不能再传递一个表示长度的数。 如果定义全局函数实现,则我们有两种方式:

一是声明一个全局变量,通过和这个全局变量作比较。二是分别声明大于4或者5的函数。显然两个办法都不太好。全局变量污染一直是很危险的,而声明多个函数显然不科学,如果有更多的需求,则需声明gt2, gt3, gt4 ...。 这个用lambda表达式似乎更好,如:

int main(int argc, char **argv)
{
	vector<string> s = {"1", "12", "123", "1234", "12345", "123456", "1234567"};
	string::size_type n = 3;
	cout << count_if(begin(s), end(s), [n](string s){return s.size() > n;});
	return 0;
}

注意这里的n并不是全局变量,所以不存在全局变量污染的问题。当然还有更好的办法,那就是利用函数对象,如:

using namespace std;
class Gt
{
	public:
		typedef string::size_type size_type;
		Gt(size_type i):n(i){};
		Gt():n(0){};
		void setN(const size_type& i) {
			n = i;
		}
		size_type getN() const{return n;}
		bool operator () (const string &s) const {return s.size() > n;}
		operator int() const { return n;}
	private:
		string::size_type n = 0;
};
inline Gt operator + (const Gt &s1, const Gt &s2)
{
	return Gt(s1.getN() + s2.getN());
}
int main(int argc, char **argv)
{
	vector<string> s = {"1", "12", "123", "1234", "12345", "123456", "1234567"};
	cout << count_if(begin(s), end(s), Gt(1)) << endl; /* > 1 */
	cout << count_if(begin(s), end(s), Gt(2)) << endl; /* > 2 */
	cout << count_if(begin(s), end(s), Gt(2) + Gt(3)) << endl; /* > 5 */
	return 0;
}

上面分别统计长度大于1,大于2,大于5的字符串数量(重载+运算符,纯属娱乐!)。

lambda表达式另外一个功能是声明局部函数。我们知道c++中是不允许在函数中嵌套定义函数的,如果要声明一个局部函数,即只能在函数内部调用,则可以用lambda实现,如声明一个min函数,返回a,b中较小值。则

#include <iostream>
using namespace std;
int main(int argc, char **argv)
{
	auto min = [](int a, int b) -> int{
		return a < b ? a : b;
	};
	cout << min(1, 2) << endl;
	cout << min(8, 2) << endl;
	return 0;
}

 

转载请注明:http://krystism.is-programmer.com/若有错误,请多多指正,谢谢!
  • 无匹配
  • 无匹配
Digital Ali 说:
2021年9月06日 17:31

Your blog has chock-a-block of useful information. I liked your blog's content as well as its look. In my opinion, this is a perfect blog in all aspects. movies123

boardmodelpaper.com 说:
2024年1月20日 14:49

The Board model paper" typically refers to a sample or model question paper that is designed by educational boards or institutions for various exams. These papers serve as practice material for students preparing for exams, providing them with an idea of the question format, difficulty level, and the type of content that may be covered in the actual examination. boardmodelpaper.com Model papers are usually created for specific subjects or courses. They cover a range of topics and chapters that students are expected to have studied during the academic term. Students often use these educational board model papers as an integral part of their exam preparation strategy, helping them familiarize themselves with the exam pattern and refine their understanding of the subject matter.

is bloxlink safe 说:
2024年3月13日 15:32

I loved as much as you’ll receive carried out right here. The sketch is tasteful, your authored subject matter stylish. nonetheless, you command get got an edginess over that you wish be delivering the following. unwell unquestionably come more formerly again as exactly the same nearly very often inside case you shield this hike.

polar sexpress 说:
2024年4月08日 19:45

The library is a testament to the power of words, which have the ability to educate, inspire, and transform.

aluguel de impressor 说:
2024年9月02日 19:47

O aluguel de impressoras pode contribuir para uma política de sustentabilidade dentro das empresas. Equipamentos mais novos tendem a ser mais eficientes em termos de consumo de energia e uso de papel, além de possibilitar uma melhor gestão de resíduos e reciclagem de suprimentos.


登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter