开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 6 天,点击查看活动详情
C++ 11 引入了 Lambda,允许我们定义内联函数,它可以被用来当作一个参数或者本地对象。
Lambda 改变了 C++ 标准库的使用方式, 一般我们使用 C++ 标准库会自己写一些准则,比如调用快速排序算法,但是具体的比较准则我们可以自己写(不写就用默认的),我们写的东西就是一些函数对象或者仿函数,而引入 C++ 11 之后,这个函数定义可以写成 Lambda 的形式,这就可以被定义在语句或者表达式里面。因此我们可以使用 Lambda 作为内联函数。
一、初识 ambda 表达式
最简单的 Lambda 表达式是无参的,形式如下
[]{
std::cout << "hello lambda" << std::endl;
}
上面的写法没有意义,如果要使用它,可以加 ()
[]{
std::cout << "hello lambda" << std::endl;
}()
但这样写看着就很没必要,所以我们通常都将它记成下面的样子,可复用,调用更为方便。
auto l = []{
std::cout << "hello lambda" << std::endl;
};
l();
二、Lambda 表达式完整形式
[capture] (parameters) mutable -> return-type {statement}
为了方便后文叙述,我们写成下面的形式
->
-
- Lambda 导入器(introducer)
- 可写入取用的外部的变量
-
传值
int x = 0; auto var =[x]{};//pass by value
-
传引用
int y = 42; auto var =[&y]{};//pass by reference
-
-
- 参数
-
- 中内容是否可以被改写
- mutable 关键字 可改动的
-
- 抛出异常
-
->
- 描述 Lambda 的返回类型
-
- 函数本体
注:
- 3、4、5 是可选的,但是这三个中如果有一个存在,则参数项 存在;三个都没有,也没有参数 可以不写
例子1 对象按值传递,
int id = 0;
auto f2 = [id]()mutable{
std::cout << "id:" << id << std::endl;
++id;
};
id = 42;
f2();
f2();
f2();
std::cout<< id<< std::endl;
- f 中最初的 id 记为 0,所以 f() 三次是 0、1、2;
- 最终打印才是后来的赋值 42;
- f 里面怎么变都不影响外面的 id;
- Lambda 的类型是匿名的函数对象 anonymous function object(or functor)
class Functor
{
private:
int id;
public:
void operator()(){
std::cout<<"id:"<<id<<std::endl;
++id;
}
};
Function f;
思考:不写 mutable 里面的 id 不能 ++ 么?
例子1
int id = 0;
auto f = [id]()mutable{
std::cout << "id:" << id << std::endl;
++id;
};
id = 42;
f2();
f2();
f2();
std::cout<< id<< std::endl;
结果:
id=0
id=1
id=2
42
例子2
int id = 0;
auto f = [&id](int parm){
std::cout << "id:" << id << std::endl;
++id;
++param;
};
id = 42;
f(7);
f(7);
f(7);
std::cout<< id<< std::endl;
结果:
id=42
id=43
id=44
45
例子2
int id = 0;
auto f = [id](){
std::cout << "id:" << id << std::endl;
++id;
};
id = 42;
f();
f();
f();
std::cout<< id<< std::endl;
上述写法错误!
总结
- 传引用这个里面的 id 受外界影响,同时里面也会影响外面;
- 按值传递,如果不加 mutable,这个外界的 id 就是只读的,不可以修改;
- lambda 表达式函数本体里面可以声明变量,可以返回数值
int tobefound = 5;
auto lambda1 = [tobefound](int val){return val == tobefound;};
写成仿函数就是下面的类里的样子, 传递 lambda 的类型
class UnNamedLocalFunction
{
int localVar;
public:
UnNamedLocalFunction(int var):localVar(var){}
bool operator()(int val)
{
return val == localVar;
}
}
调用
UnNamedLocalFunction lambda2(tobefound);
bool b1 = lambda1(5);
bool b2 = lambda2(5);
可以在程序中一起看看结果。
三、lambda 表达式通过捕获列表捕获变量的范围说明
- [] 不捕获任何变量。
- [&] 捕获外部作用域中所有变量,并作为引用在函数体中使用(按引用捕获)。
- [=] 捕获外部作用域中所有变量,并作为副本在函数体中使用(按值捕获)。
- [=,&foo] 按值捕获外部作用域中所有变量,并按引用捕获 foo 变量。
- [bar] 按值捕获 bar 变量,同时不捕获其他变量。
- [this] 捕获当前类中的 this 指针,让 lambda 表达式拥有和当前类成员函数同样的访问权限。如果已经使用了 & 或者 =,就默认添加此选项。捕获 this 的目的是可以在 lamda 中使用当前类的成员函数和成员变量。