目录
一.lambda表达式
1.格式
2. lambda表达式各部分说明
3.举例
(1)例子1:相加函数
(2)[ ]捕捉列表 例子2:交换函数
仿函数比较,lambda更易懂
4.lambda注意点
5.底层原理
二.包装器
1.可调用类型对象
2.function包装器
解决useF问题
3.包装器改装逆波兰表达式
4.bind 绑定
(1)调整可调用对象参数的个数
(2)调整可调用对象参数的顺序(用处不大)
bind总代码:
lambda表达式就是定义了一个可调用的匿名函数,一般在局部。
[]{}是最简单的lambda表达式,但是该lambda表达式没有任何意义
[capture-list] (parameters) mutable -> return-type { statement }
捕捉列表 参数 去const(单词意思易变的) 返回值 函数体
auto Add1 = [ ](int x, int y)->int {return (x + y); };
int a = 0, b = 200;
// [capture-list] (parameters) mutable -> return-type { statement }
// 捕捉列表 参数 返回值 函数体
// 一般是局部匿名函数 也可以写到全局
auto Add1 = [](int x, int y)->double {return (x + y) / 3.0; };
auto Add2 = [](int x, int y)->int {return (x + y) / 3.0; };//传参写法
auto Add3 = [a, b] {return (a + b) / 3.0; };//捕捉变量写法
cout << Add1(a, b) << endl;
cout << Add2(a, b) << endl;
cout << Add3() << endl;
3,4,5,6是几种捕捉方式
1. auto Swap1 = [](int& x, int& y){
int tmp = x;
x = y;
y = tmp;
};
Swap1(a, b);
cout << a << " " << b << endl;
2. mutable 只是让传值捕捉变量const属性去掉了,但是捕捉的a,b仍是拷贝,外部的a,b无法被修改
/*auto Swap2 = [a, b]()mutable{
int tmp = a;
a = b;
b = tmp;
};*/
用引用的方式捕捉:
auto Swap2 = [&a, &b]{
int tmp = a;
a = b;
b = tmp;
};
Swap2();
cout << a << " " << b << endl;
3. int c =2, d=3, e=4, f=5, g=6, ret;
传值捕捉全部对象
auto Func1 = [=]{
return c + d*e / f + g;
};
cout << Func1() << endl;
4. 传引用捕捉全部对象
auto Func2 = [&]{
ret = c + d*e / f + g;
};
Func2();
cout << ret << endl;
5. 混着捕捉
auto Func3 = [c, d, &ret]{
ret = c + d;
};
Func3();
cout << ret << endl;
6. ret传引用捕捉 其他全部传值捕捉
auto Func4 = [=, &ret]{
ret = c + d*e / f + g;
//c = 1;
};
Func4();
cout << ret << endl;
(greater是排降序,less是排升序)
比如:仿函数 sort(v.begin(), v.end(), ComparePriceLess()); 可以写成sort(v.begin(), v.end(), [](const Goods& g1, const Goods& g2){return g1._price < g2._price; });
struct Goods
{
string _name; // 名字
double _price; // 价格
int _evaluate; // 评价
Goods(const char* str, double price, int evaluate)
:_name(str)
, _price(price)
, _evaluate(evaluate)
{}
};
struct Compare1
{
bool operator()(const Goods& gl, const Goods& gr)
{
return gl._evaluate < gr._evaluate;
}
};
struct ComparePriceLess
{
bool operator()(const Goods& gl, const Goods& gr)
{
return gl._price < gr._price;
}
};
struct ComparePriceGreater
{
bool operator()(const Goods& gl, const Goods& gr)
{
return gl._price > gr._price;
}
};
int main()
{
vector v = { Goods( "苹果", 2.1, 5 ), { "香蕉", 3, 4 }, { "橙子", 2.2, 3 }, { "菠萝", 1.5, 4 } };
//sort(v.begin(), v.end()); 自定义类型没重载<不能用less或者greater
1.正常用仿函数写sort:
sort(v.begin(), v.end(), Compare1());
sort(v.begin(), v.end(), ComparePriceLess());
sort(v.begin(), v.end(), ComparePriceGreater());
2.用lambda代替仿函数:
(1)常规写法
auto com1 = [](const Goods& g1, const Goods& g2){return g1._price < g2._price; };
sort(v.begin(), v.end(), com1);
(2)匿名对象写法
sort(v.begin(), v.end(), [](const Goods& g1, const Goods& g2){
return g1._price < g2._price; });
cout << endl;
sort(v.begin(), v.end(), [](const Goods& g1, const Goods& g2){
return g1._price > g2._price; });
cout << endl;
sort(v.begin(), v.end(), [](const Goods& g1, const Goods& g2){
return g1._evaluate < g2._evaluate; });
cout << endl;
sort(v.begin(), v.end(), [](const Goods& g1, const Goods& g2){
return g1._evaluate > g2._evaluate; });
cout << endl;
return 0;
}
但是允许使用lambda表达式拷贝构造
也可以将lambda表达式赋值给相同类型的函数指针,了解一下,一般不建议这么用,意义不大
void (*PF)();
int main()
{
auto f1 = [] {cout << "hello world" << endl; };
auto f2 = [] {cout << "hello world" << endl; };
f1 = f2; //错误,lambda对象之间不能相互赋值,编译失败--->提示找不到operator=()
auto f3(f2); //正确,允许使用一个lambda表达式拷贝构造一个新的副本
f3();
// 可以将lambda表达式赋值给相同类型的函数指针,了解一下,一般不建议这么用
PF = f2; //上面有void (*PF)(); PF和f2都是无类型无返回值
PF();
return 0;
}
lambda表达式底层是一个仿函数。每个lambda都会被转换成一个仿函数类型,仿函数类名称lambda+ uuid。uuid是生成的随机不同的字符串,防止冲突
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.49;
Rate r1(rate);
r1(10000, 2);
// lamber
auto r2 = [=](double monty, int year)->double {return monty * rate * year;};
r2(10000, 2);
return 0;
}
仿函数:函数对象,又称为仿函数,即可以像函数一样使用的对象,就是在类中重载了operator()运算符的类对象。
r1就是仿函数,这里调用的是重载的了operator()运算符。lambda底层则是被转换成了一个 类名称叫lambda+ uuid 的仿函数,r2(10000, 2);就是调用了此仿函数的operator()运算符
1、函数指针
2、仿函数对象
3、lambda
template
T useF(F f, T x)
{
static int count = 0;
cout << "count:" << ++count << endl;
cout << "count:" << &count << endl;
return f(x);
}
double f(double i)
{
return i / 2;
}
struct Functor
{
double operator()(double d)
{
return d / 3;
}
};
int main()
{
// 函数名
cout << useF(f, 11.11) << endl;
// 函数对象
cout << useF(Functor(), 11.11) << endl;
// lamber表达式
cout << useF([](double d)->double{ return d / 4; }, 11.11) << endl;
return 0;
}
通过上面的程序验证,我们会发现useF函数模板实例化了三份。
把对应的可调函数 函数指针/仿函数/lambda 包装起来使用,比如包装lambda:
std::function func5 = [](int a, int b) {return a + b; }; ——包装
cout << func5(100, 200) << endl; ——包装以后直接使用
包装器用途:统一类型,
std::function
第一个int是被调用函数的返回类型,小括号俩int是被调用函数的形参类型,f是要包的那个函数。
template
int f(int a, int b)
{
return a + b;
}
struct Functor
{
public:
int operator() (int a, int b)
{
return a + b;
}
};
class Plus
{
public:
static int plusi(int a, int b)
{
return a + b;
}
double plusd(double a, double b)
{
return a + b;
}
};
int main()
{
std::function func1 = f;
cout << func1(1, 2) << endl;
std::function func2 = Functor();
cout << func2(10, 20) << endl;
静态成员函数包装可以加&也可以不加(建议都加&)
std::function func3 = &Plus::plusi;
cout << func3(100, 200) << endl;
规定:非静态成员函数包装必须加&,因为有this指针,所以参数多传一个域
std::function func4 = &Plus::plusd;
cout << func4(Plus(), 100.11, 200.11) << endl;//Plus()是匿名对象,有对象才能调函数
std::function func5 = [](int a, int b) {return a + b; };
cout << func5(100, 200) << endl;
return 0;
}
解决:包装器,把函数/仿函数/lambda表达式 包装成一个类型,只实例化一份
#include
template
T useF(F f, T x)
{
static int count = 0;
cout << "count:" << ++count << endl;
cout << "count:" << &count << endl;
return f(x);
}
double f(double i)
{
return i / 2;
}
struct Functor
{
double operator()(double d)
{
return d / 3;
}
};
int main()
{
// 函数名
std::function func1 = f;
cout << useF(func1, 11.11) << endl;
// 函数对象
std::function func2 = Functor();
cout << useF(func2, 11.11) << endl;
// lamber表达式
std::function func3 = [](double d)->double{ return d / 4; };
cout << useF(func3, 11.11) << endl;
return 0;
}
150. 逆波兰表达式求值
例如:
["4","13","5","/","+"] ,把4,13,5入栈,取到“/”后,13/5=2,2入栈,栈里有:4,2;取到 “+” 后,4+2=6,结果为6
class Solution {
public:
int evalRPN(vector& tokens) {
stack st;
map> opFuncMap={
{"+",[](long long a,long long b){return a+b;}},
{"-",[](long long a,long long b){return a-b;}},
{"*",[](long long a,long long b){return a*b;}},
{"/",[](long long a,long long b){return a/b;}}
};
for(auto& e: tokens)
{
if(opFuncMap.count(e))
{
int right=st.top();
st.pop();
int left=st.top();
st.pop();
st.push(opFuncMap[e](left,right));
}
else
{
st.push(stoll(e));
}
}
return st.top();
}
};
作用:调整可调用对象参数的个数和顺序
fn是可调用对象,Args&&... args是参数包
(可调用类型对象:1、函数指针 2、仿函数对象 3、lambda)
正常情况下面都是传两个参数:
int f(int a, int b)
{
return a - b;
}
struct Functor
{
public:
int operator() (int a, int b)
{
return a + b;
}
};
class Plus
{
public:
Plus(int x = 2)
:_x(x)
{}
int plusi(int a, int b)
{
return (a + b)*_x;
}
private:
int _x;
};
int main()
std::function func1 = f;
cout << func1(1, 2) << endl;
std::function func2 = Functor();
cout << func2(10, 20) << endl;
// 3个参数
std::function func3 = &Plus::plusi;
cout << func3(Plus(), 100, 200) << endl;
就导致定义map时,map的second类型是两个参数的包装器,则这3个参数的传不进去,只能通过bind解决:
map> opFuncMap =
{
{ "普通函数指针", f },
{ "函数对象", Functor() },
{ "成员函数指针", std::bind(&Plus::plusi, Plus(10), placeholders::_1, placeholders::_2) }
};
改成传2个参数的:
2个参数 这里相当于绑定了第一个参数10;1个参数 这里相当于绑定了第一个参数为10,第二个参数为30;
// 2个参数
std::function func4 = std::bind(&Plus::plusi, Plus(10), placeholders::_1, placeholders::_2);
cout << func4(10,20) << endl;
如果用bind改成传一个参数的:
// 1个参数
std::function func5 = std::bind(&Plus::plusi, Plus(10),
30, placeholders::_1);
cout << func5(200) << endl;
此时66传给_1,77传给_2,f函数中a接收_2的77,b接收_2的66
int f(int a, int b)
{
return a - b;
}
int main()
{
未调整:
std::function func1 = f;
cout << func1(66, 77) << endl;
调整顺序:
// 调整顺序 -- 用处不大
std::function func6 = std::bind(f, placeholders::_2,
placeholders::_1);
cout << func6(66, 77) << endl;
}
int f(int a, int b)
{
return a - b;
}
struct Functor
{
public:
int operator() (int a, int b)
{
return a + b;
}
};
class Plus
{
public:
Plus(int x = 2)
:_x(x)
{}
int plusi(int a, int b)
{
return (a + b)*_x;
}
private:
int _x;
};
int main()
{
std::function func1 = f;
cout << func1(1, 2) << endl;
std::function func2 = Functor();
cout << func2(10, 20) << endl;
// 3个参数
std::function func3 = &Plus::plusi;
cout << func3(Plus(), 100, 200) << endl;
// 调整可调用对象的参数个数和顺序
// _1 _2 _3... 表示你要自己传的那些参数,_1表示第一个参数传给_1
// 调整个数
// 2个参数
std::function func4 = std::bind(&Plus::plusi, Plus(10),
placeholders::_1, placeholders::_2);
// 1个参数
std::function func5 = std::bind(&Plus::plusi, Plus(10),
10, placeholders::_1);
cout << func5(200) << endl;
// 调整顺序 -- 用处不大
std::function func6 = std::bind(f, placeholders::_2,
placeholders::_1);
cout << func1(66, 77) << endl;
cout << func6(66, 77) << endl;
map> opFuncMap =
{
{ "普通函数指针", f },
{ "函数对象", Functor() },
{ "成员函数指针", std::bind(&Plus::plusi, Plus(10), placeholders::_1, placeholders::_2) }
};
cout << opFuncMap["普通函数指针"](1, 2) << endl;
cout << opFuncMap["函数对象"](1, 2) << endl;
cout << opFuncMap["成员函数指针"](1, 2) << endl;
return 0;
}