《C++11标准库》3.1.10 Lambda,Capture

C++11引入了 lambda,允许 inline 函数的定义式被用作为一个参数,或是一个 local 对象。

Lambda 改变了C++标准库的用法。比如使用 lambda搭配 STL算法和容器,使用 lambda 定义并发代码。

Lambda 的语法

所谓的 lambda 是一份功能定义式,可被定义于语句或者表达式内部。因此,你可以拿 lambda当作 inline 函数使用。

最小型的 lambda 函数没有参数,什么也不做,例如:

[] { 
     std::cout << " Hello Lambda " << std::endl ;
   };

可以像使用函数一样使用它:

[] { 
     std::cout << " Hello Lambda " << std::endl ;
   } ();

 

或者把它传递给对象,使之能被调用:

auto L =[] {
              std::cout << "hello lambda" << std::endl;
           };
.....
L();

 如上例子,lambda 总是由一个所谓的 lambda introducer()(捕获) 引入:那是一组方括号,你可以在其内指明一个所谓的 capture ,用来在 lambda 内部访问 ”nonstatic 外部对象“。如果无须访问外部数据,这组方括号可以为空,就如同上例所示。Static 对象,诸如 std::cout,是可以被使用的。

lambda 表达式基本语法:

[ 捕获 ] ( 形参 )->ret { 函数体 };

捕获 函数体 之间 ,你可以指明 捕获的变量 或 形参 ,或者一份 异常明细 或 属性说明符 以及返回类型。但是这一切都是可有可无,但如果其中一个出现了,参数所需的小括号就必须出现,因此 lambda 语法也可以是:

[...] {....}
也可以是
[...] (...) mutable throwSpec ->Type {...}
auto L =[] ( cosnt std::string& s) {
              std::cout << "hello lambda" << std::endl;
           };
.....
L("hello lambda");

注:lambda 不可以是 template 。你始终指明所有类型。

      Lambda 也可以返回某物。但你不需要指明返回类型,该类型会根据返回值被自动推导出来。例如:下面的 lambda 的返回类型是 int;

[] {
    return 42;
   } 

如果一定想指明一个返回类型,可使用C++语法,一般函数也可以使用如方式:

例如如下代码返回值为42.0

[] () ->double  {
    retutn 42;
}

这样一来,你就必须指明返回值类型,放在实参所需的小括号以及字符->后。

在参数和返回类型指示或函数体之间,你可以写出一份异常明细。尽管自C++11起不推荐这样做。

Capture (用以访问外部作用域)

在 [  ]  内,你可以知名一个 capture (捕获)来处理外部作用域内未被传递为实参的数据,有以下类别:

    (1).[var]表示值传递方式捕捉变量var;
    (2).[=]表示值传递方式捕捉所有父作用域的变量(包括this);
    (3).[&var]表示引用传递捕捉变量var;
    (4).[&]表示引用传递方式捕捉所有父作用域的变量(包括this);
    (5).[this]表示值传递方式捕捉当前的this指针。

例如:

	int x = 0;
	int y = 42;
	auto qqq = [x, &y] {
		std::cout << "X:" << x << std::endl;
		std::cout << "Y:" << y << std::endl;
		++y;//引用传递操作原数据,即原对象 y
		    //x仅是一份拷贝,所以只能使用x而不能对进行操作,例如++x;
	}

由于 x 采用的是值传递(拷贝),在 lambda 内部 x可作为右值进行使用,而不能成为一个左值使用。所以

在lambda中 std::cout << x+y << std::endl;可以使用:
但是对于 x++,x=x+y 等语句会出现编译错误。

而对于 y 以引用方式传递,所以它可以作为左值使用,也可作为右值使用,并且对它的改动会影响外部。

对于 capture 你还可以混合使用,但各权限之间不能包含。

例如:

可以使用[ =,&y ]取代[ x,&y ] ,含义为y以引用方式传递,而其他所有父类实参以值传递(拷贝)

如果想要获得值传递和引用传递的混合体,可以声明 lambda 为 mutable 

	int id = 0;
	auto f = [id]()mutable {
		std::cout << "id:" << id << std::endl;
		++id;
	};
	id = 42;
	f();
	f();
	std::cout << "id:" << id << endl;

输出结果为:

 

 对于 mutable 可以使传入参数成为一个可修改的左值,且不对外部对象产生影响。

对于上述例子可写为以下 function object

class
{
private:
	int id;//从外部拷贝;
public:
	void operator()()//对 () 进行重载
	{
		std::cout << "id:" << id << std::endl;
		++id;
	}
};

由于 mutable 的缘故,operator() 被定义为一个 non-const 成员函数,那意味着对 id 的修改是可能的,若没有 mutable 那么 operator()就成为了一个 const 成员函数,那么对于以值传递的对象只能进行读取操作,而不能修改。

Lambda的类型

Lambda 的类型,是一个不具名的函数对象,每个对象的类型都是独一无二的。

如果想要声明一个 Lambda 的对象,可借用 template 或者 auto。

想要获取 Lambda 的类型,可使用C++标准库提供的 std::function<>class template,这个类模板提供了”明确指出函数的返回类型为lambda“的唯一方法:

例如:

使用前需包含头文件 

#include<functional>

std::function<int(int, int)> returnLambda()
{
	return [](int x, int y) {
		return x * y;
	};
}


int main()
{
	auto RL = returnLambda();

	std::cout << RL(6, 7) << std::endl;

	return 0;


}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值