万众瞩目的C++11特辑来了,本章将继续讲解C++11更新的内容,不过C++11的内容也快接近尾声了。
目录
10。lambda表达式
11。lambda捕捉列表[]
捕捉列表说明
lambda捕捉列表实际应用
10。lambda表达式
#include<iostream>
using namespace std;
#include<algorithm>
#include<vector>
struct Goods
{
string _name; // 名字
double _price; // 价格
int _evaluate; // 评价
//...
Goods(const char* str, double price, int evaluate)
:_name(str)
, _price(price)
, _evaluate(evaluate)
{}
};
int main()
{
//lambda表达式
// lambda 匿名函数的对象, 所以肯定有类型,所以肯定有返回值
//即返回一个lambda类型的对象
auto ret = [](int x, int y)->int {return x + y; };
//为什么用auto自动推导呢,因为lambda的类型lambda_uuid过于复杂了,详情请看汇编
//这个切记lambda的返回值不是返回函数体里面运算得出了类型,虽然return了
cout << ret(1, 1) << endl;
cout << ret(3, 1) << endl;
//上面展示的是lambda表达式的完整形式
//最前面的捕捉列表,没有捕捉对象可以没有任何东西,但是[]必须写上
//后面的参数部分,确实不需要传参可以不写,明确函数体返回值的可以不写->返回值
//函数体部分不可以省略
//所以只有[]和函数体是必须写上的
// 返回值类型可自动推导类型,所以可以省略
// 无参数可以省略
auto it = []
{
cout << "wfwfwq" << endl;
cout << "wfwfwq" << endl;
cout << "wfwfwq" << endl;
cout << "wfwfwq" << endl;
//return 0;//有没有return都无所谓的,只要返回值确定或者无返回值
};
it();//外部调用方法
return 0;
}
//通过观察底层汇编可以发现lambda和仿函数的实现有点像,
//所以这两个是可以互相替代使用的
然而我们会发现,在之前使用的库里面的sort函数就使用了仿函数,所以我们可以使用lambda表达式对其进行改造。
struct comp1//比较价格的升序
{
bool operator()(const Goods& gl, const Goods& gr)
{
return gl._price < gr._price;
}
};
struct comp2//比较价格的降序
{
bool operator()(const Goods& gl, const Goods& gr)
{
return gl._price > gr._price;
}
};
int main()
{
vector<Goods> v = { { "苹果", 2.1, 5 }, { "香蕉", 3, 4 }, { "橙子", 2.2, 3 }, { "菠萝", 1.5, 4 } };
sort(v.begin(), v.end(), comp1());
sort(v.begin(), v.end(), [](const Goods& gl, const Goods& gr)
{
return gl._price > gr._price;
});
return 0;
}
以下为调试结果:
//使用lambda表达式的优点是便于使用者马上就可以看出在进行什么操作,升序排列降序排列什么的
//比较直观
//其实也不需要去看底层这个comp1作为一个类,comp1()就是匿名函数对象,那和lambda的本质不是一样了吗
11。lambda捕捉列表[]
//接着聊一下捕捉列表是个什么东西,有什么作用
//捕捉列表的本质就是在初始化函数的参数!!!
int main()
{
int a = 2;
int b = 5;
auto swap1 = [](int& x, int& y)
{
//只能用当前lambda局部域和捕捉的对象
int temp = x;
x = y;
y = temp;
};
swap1(a, b);
cout << a << endl;
cout << b << endl;
int c = 6;
int d = 7;
//发现swap1将两个值交换了
auto swap2 = [c, d]()mutable
{
// 只能用当前lambda局部域和捕捉的对象
int temp = c;
c = d;
d = temp;
//上面报错的信息为必须是可修改的左值
//说明传值捕捉指定参数个体本质是一种拷贝,并且const修饰了
//解决办法在[]后面加上()mutable,mutable的作用是去除const属性
};
swap2();//传值捕捉还是需要调用的,只是参数固定了,不需要写了(不要忘了调用)
cout << c << endl;
cout << d << endl;
//发现没有交换成功, 结合上面swap1交换成功的例子可以看出传值捕捉
//修改了不会影响外面被捕捉的值,因为是一种拷贝,如果执意要改需要传引用捕捉
//这里侧面体现了mutable和传值捕捉都没有什么实际价值
auto swap3 = [&c, &d]//这里不是取地址是引用
{
int tmp = c;
c = d;
d = tmp;
};
swap3();
cout << c << endl;
cout << d << endl;
return 0;
}
// 只能用当前lambda局部域和捕捉的对象和全局对象
捕捉列表说明
int main()
{
//还有其他的捕捉方式
int a = 0;
int b = 1, c = 1;
int d = 2;
// 所有值传值捕捉
auto func1 = [=]
{
int ret = a + b + c + d;
return ret;//如果要取到ret的值就需要返回,因为出了func1函数的局部域就销毁了
};
// 所有值传引用捕捉
auto func2 = [&]
{
a++;
b++;
c++;
d++;
int ret = a + b + c + d;
return ret;//如果要取到ret的值就需要返回,因为出了func1函数的局部域就销毁了
};
// 混合捕捉
auto func3 = [&a, b]
{
a++;
//b++;//无法修改
int ret = a + b;
return ret;//如果要取到ret的值就需要返回,因为出了func1函数的局部域就销毁了
};
// 混合捕捉
// 除d以外所有值以引用方式捕捉,d用传值捕捉
auto func4 = [&, d]
{
a++;
b++;
c++;
//d++;
int ret = a + b + c + d;
return ret;//如果要取到ret的值就需要返回,因为出了func1函数的局部域就销毁了
};
// 除d以外所有值以传值方式捕捉,d用传引用捕捉
auto func5 = [=, &d]() mutable
{
a++;
b++;
c++;
d++;
int ret = a + b + c + d;
};
int p1 = func1();
int p2 = func2();
int p3 = func3();
int p4 = func4();
cout << p1 << endl;
return 0;
//太多组合方式了
}
lambda捕捉列表实际应用
下面的例子是一个计算利息的程序(后面会不断的使用这个例子)
class Rate
{
public:
Rate(double rate)
: _rate(rate)//一般是放在下面
{}
double operator()(double money, int year)
{
return money * _rate * year;//计算当年的利息
}
private:
double _rate;
};
int main()
{
// 函数对象
double rate = 0.015;
Rate r1(rate);
cout << r1(10000, 2) << endl;
// lambda[]捕捉在全局域捕捉
auto r2 = [rate](double monty, int year)->double
{
return monty * rate * year;
};
cout << r2(10000, 2) << endl;
int x = 1, y = 2;
//执行之后发现捕捉列表也不是什么都捕捉的,对函数体里面有用的变量才捕捉
auto r3 = [=](double monty, int year)->double
{
return monty * rate * year;
};
cout << r3(10000, 2) << endl;
return 0;
}
现在解决一下关于lambda对象的类型的问题:请看下图
可以看到图片//lambda那里有一个call <lambda_什么什么>很长的一串字符,这个就是lambda对象的类型,这个可以看成是一个类(因为有类操作符::),类就是类型,由于太长了就简称lambda_uuid,所有lambda是有类型的并且可以取到的