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;
}