一种可调用对象,定义了一个匿名函数,并且可以捕获一定范围内的变量;
auto f = [](int a)->int{return a + 1};
cout << f(1) << endl;
特点
格式
通过捕获列表来捕获一定范围内的变量;范围指的什么?
[]表示不捕获任何变量;但是不包括静态局部变量,lambda可以直接使用局部静态变量;局部静态变量是不需要捕获的;
int i = 9;
auto f = []{return i}; // 出错,无法捕获外部变量,不认识这个i在哪里定义;
[&]捕获外部作用域中所有变量,并作为引用在函数体内使用;
int i = 9;
auto f = [&]{
i = 5;
return i; //因为&的存在,允许给i赋值,从而就改变i的值
};
[=]捕获外部作用域中所有变量,作为副本按值在函数中使用,也就是可以用它的值,但是不允许给它赋值;
int i = 9;
auto f = [=]{
//i = 5; //报错,非法;
return i;
}
[this]一般用于类中,捕获当前类中this指针,让lambda表达式有和当前类成员函数同样的访问权限;如果[]中已经使用了&或者=,就默认使用了this;捕获this的目的就是为了让lambda使用成员函数和变量;
class Test
{
public:
int m_i = 5;
void func(int x, int y)
{
auto f = [this]{
return m_i; //引用this存在,合法
};
cout << f() << endl;
}
}
[变量名]如果是多个变量名,彼此之间用逗号分隔。表示按值捕获变量名代表的变量,同时不捕获其他变量;
[&变量名]:按引用捕获变量名代表的变量,同时不捕获其他变量;
[=, &变量名]:按值捕获所有外部变量,但按引用捕获&中所指的变量,等号必须写在开头位置,这个位置表示默认捕获方式(隐式捕获方式);后续其他都是显示捕获方式;
[&, 变量名]:按引用来捕获所有外部变量,但是按值来捕获后面的变量;
总结:
? lambda表达式对能访问的外部变量控制非常细致
int x = 5;
auto f = [=]{ //捕获时刻,x的值就已经赋值到表达式中了;
return x;
}
x = 10;
cout << f() << endl; //实际是5;
int x = 5;
auto f = [&]{
return x;
}
x = 10;
cout << f() << endl; //x = 10;
//mutable 易变的
int x = 5;
auto f = [=]() mutable //要加mutable,()不能省略;
{
x = 6;
return x;
}
C++11中lambda表达式的类型被称为闭包类型;
闭包:函数内的函数(可调用对象);本质上就是lambda表达式创建的运行时期的对象;
lambda表达式是一种比较特殊的,匿名的,类类型的对象(也就是定义了一个类类型,又生成了一个匿名的该类类型的对象【闭包】)
可以认为它是一种带有operator()的类类型对象;也就是仿函数对象;
也可以用std::function和std::bind来保存和调用lambda表达式;每个lambda都会触发编译器生成一个独一无二的类类型;
std::function<int(int)> fc = [](int x) {return x;};
cout << fc(15) << endl;
//bind第一个参数是函数指针,第二个参数是真正的函数参数
std::function<int(int)> fc_bind = std::bind(
[](int x) {return x;}, 16
};
cout << fc(15) << endl;
cout << fc_bind(16) << endl;
lambda这种语法,可以就地的定义匿名函数,就地封装短小的功能闭包;
不捕获任何变量的lambda表达式,也就是捕获列表为空,可以转换成一个普通的函数指针;
using func_type = int(*) (int); //定义一个函数指针类型
func_type fp = [](int x) {return x;};
cout << fp(1) << endl;
语法糖
void myfunc(int i)
{
cout << i << endl;
}
vector<int> my_vector = {10, 20, 30, 40, 50};
for_each(my_vector.begin(), my_vector.end(), myfunc);
int isum = 0;
for_each(my_vector.begin(), my_vector.end(), [&isum](int val){
isum += val;
cout <<val << " ";
});
cout << endl;
cout << isum << endl;
vector<int> my_vector = {10, 20, 30, 40, 50};
auto res = find_if(my_vector.begin(), my_vector.end(), [](int val){
cout << val << endl;
if(val > 15) return true; //返回true,停止遍历
return false; //只要返回false,find_if就不停的遍历,直到遍历完
//如果第三个参数可调用参数返回true,find_if就停止遍历;
})
总结:善用lambda表达式,让代码更简洁,提高效率
捕获外部作用域中所有变量,不包括静态变量,并作为引用在lambda表达式中使用;
按照引用这种捕获方式,会导致lambda表达式包含绑定到局部变量的引用;
引用捕获超出范围也叫做 引用悬空;
std::vector<std::function<bool(int)>> gv; //全局变量,每个元素都是个function,每个function给进去的int,返回的是bool;
void func()
{
srand((unsigned)time(NULL));
int tmp_value = rand() % 6;
gv.push_back(
[&](int tv){
if(tv % tmp_value == 0) return true;
return false;
});
}
int main()
{
func();
//cout << gv[0](10) << endl; 非法调用,会出问题 采用按值捕获可以解决;[=]
}
C++14允许在lambda表达式的形参列表中使用auto
捕获:只针对在创建lambda表达式的作用域内可见的非静态局部变量(包括形参);
this指向对象本身,所以这里用[=]捕捉的是this指针值;
用来[=]或者[&]等价于用了this
std::vector<std::function<bool(int)>> gv; //全局变量,每个元素都是个function,每个function给进去的int,返回的是bool;
class AT
{
public:
int m_value = 7;
void addItem()
{
gv.push_back([=](auto tv)){ //=相当于有this
//=按值捕获
//没有等号不能访问成员变量
//
cout << m_value << endl;
if(tv % m_value == 0)
{
return true;
}
return false;
}
};
}
int main()
{
AT *pat = new AT();
pat -> addItem();
cout << gv[0](10) << endl; //lambda表达式执行正确与否,取决于pat对象是否存在;只有pat对象存在,表达式执行才正确;
delete pat;
}
std::vector<std::function<bool(int)>> gv; //全局变量,每个元素都是个function,每个function给进去的int,返回的是bool;
class AT
{
public:
int m_v = 7;
void addItem()
{
auto m_value = m_v;
gv.push_back([=](auto tv)){ //=相当于有this
//=按值捕获
//没有等号不能访问成员变量
//
cout << m_value << endl;
if(tv % m_value == 0)
{
return true;
}
return false;
}
};
}
int main()
{
AT *pat = new AT();
pat -> addItem();
cout << gv[0](10) << endl; //lambda表达式执行正确与否,取决于pat对象是否存在;只有pat对象存在,表达式执行才正确;
delete pat;
}
std::vector<std::function<bool(int)>> gv; //全局变量,每个元素都是个function,每个function给进去的int,返回的是bool;
class AT
{
public:
int m_value = 7;
void addItem()
{
gv.push_back([abc = m_value](auto tv)){ //=相当于有this
//=按值捕获
//没有等号不能访问成员变量
//
cout << m_value << endl;
if(tv % m_value == 0)
{
return true;
}
return false;
}
};
}
int main()
{
AT *pat = new AT();
pat -> addItem();
cout << gv[0](10) << endl; //lambda表达式执行正确与否,取决于pat对象是否存在;只有pat对象存在,表达式执行才正确;
delete pat;
}
捕获是不包括静态局部变量的,也就是说静态局部变量是不能被捕获的;但是可以再lambda中使用,另外,静态局部变量是保存在静态存储区,它的有效期一直到程序结束;
静态局部变量的使用类似于按引用捕获;
std::vector<std::function<bool(int)>> gv; //全局变量,每个元素都是个function,每个function给进去的int,返回的是bool;
void func()
{
srand((unsigned)time(NULL));
static int tmp_value = rand() % 6; //静态变量是不需要捕获的;捕获不到
gv.push_back(
[&](int tv){
cout << tmp_value << endl;
if(tv % tmp_value == 0) return true;
return false;
});
tmp_value++;
cout << tmp_value << endl;
}
int main()
{
func();
cout << gv[0](10) << endl; //按引用捕获的效果
}
原文:https://www.cnblogs.com/Trevo/p/13435679.html