1.lambda
我们如果想要给一个自定义的元素排序,那么应该怎么排呢
先举个例子:
struct Goods
{
string _name; // 名字
double _price; // 价格
int _evaluate; // 评价
Goods(const char* str, double price, int evaluate)
:_name(str)
, _price(price)
, _evaluate(evaluate)
{}
};
struct Comparepriceless
{
bool operator()(const Goods& g1, const Goods& g2)
{
return g1._price < g2._price;
}
};
int main()
{
vector<Goods> v = { { "苹果", 2.1, 5 }, { "香蕉", 3, 4 }, { "橙子", 2.2,
3 }, { "菠萝", 1.5, 4 } };
sort(v.begin(), v.end(), Comparepriceless());
}
这里的Comparepriceless(),这是在干什么呢:sort要接受的是一个函数,而我们现在Comparepriceless是一个类,所以是用它调用operator(),我们此时用的是仿函数,然后用匿名对象调用operator,但是不能用有名对象的operator(),这是因为你()要传参数,它需要的是这样的:这样才能调用到,但是我们仿函数会自动反过来调用
这是我们平常写的,如果学习了c++11的话我们有了新的写法,就是用lambda写 ,比较方便用于多个不同种类的那种,有利之处类似于多态那种感觉。
int main()
{
vector<Goods> v = { { "苹果", 2.1, 5 }, { "香蕉", 3, 4 }, { "橙子", 2.2,
3 }, { "菠萝", 1.5, 4 } };
for (auto e : v)
{
cout << e._name << " ";
}
cout << endl;
sort(v.begin(), v.end(), [](const Goods& g1, const Goods& g2)->bool
{
return g1._price > g2._price;
});
for (auto e : v)
{
cout << e._name << " ";
}
return 0;
}
2接着我们要详细写一下lambda的各种情况以及使用情况
int main()
{
//最简单的lambda
[] {};//从中我们可以知道 参数列表 返回类型 都是可以省略的
int a = 10, b = 20, c = 30;
//省略返回类型:
auto d = [](int x, int y) {return x + y; };
cout << d(a, b) << endl;
//使用lambda 对于参数的两种方式
auto e = [](int x, int y)->int//传参
{
return x + y;
};
cout << e(a, b)<<endl;
auto la=[a, b]()->int//追踪 追踪到的是原变量的拷贝,具有cosnt性质
{
return a + b;
};
cout << la() << endl;
//全追踪
auto f = [=] {return a + b + c; };
cout << f() << endl;
//全追踪 改变常量 只改变拷贝,实际改变需要引用
auto g = [=]()mutable {a++; };
//引用追踪 因为引用符号和取地址符号重复了,
auto m = [&] {a++, b++, c++; };
m();
cout << a << " " << b << " " << c << endl;
}
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;
}
二:function包装器
#include<functional>
struct Functor
{
public:
int operator() (int a, int b)
{
return a + b;
}
};
int f(int a, int b)
{
return a + b;
}
class Plus
{
public:
static int plusi(int a, int b)//没有 this
{
return a + b;
}
double plusd(double a, double b)
{
return a + b;
}
};
int main()
{
//包装三种 函数指针 仿函数 lambda
function<int(int, int)> f1 = f;
function<int(int, int)>f2 = Functor();
function<int(int, int)> f3 = [](int x, int y) {return x + y; };
}
让我们以一道题看看function 的作用:LCR 036. 逆波兰表达式求值 - 力扣(LeetCode)
class Solution {
public:
int evalRPN(vector<string>& tokens)
{
stack<int> st;
map<string,function<int(int,int)>> m =
{
{"+",[](int x,int y)->int{return x+y;}},
{"-",[](int x,int y)->int{return x-y;}},
{"*",[](int x,int y)->int{return x*y;}},
{"/",[](int x,int y)->int{return x/y;}}
};
for(auto& e:tokens)
{
if(m.count(e))
{
int front=st.top();
st.pop();
int second=st.top();
st.pop();
int ret=m[e](second,front);
st.push(ret);
}
else
{
st.push(stoi(e));
}
}
return st.top();
}
};
function 对非静态成员函数封装的时候,要考虑隐含的tiis指针 、
可以传指针,也可以传对象:原因是function不是直接传参调用函数的,它会把函数指针当作成员变量存储,然后再用对象或者指针来调用对应的函数,它会自动反过来调用。
class Plus
{
public:
static int plusi(int a, int b)//没有 this
{
return a + b;
}
double plusd(double a, double b)
{
return a + b;
}
};
int main()
{
//function 主要是为了调用函数,就是封装函数,方便每次使用,
//一共有三个 :仿函数 函数指针 lambda ,每次使用function的时候都需要传函数指针 不如用bind 也是调用函数
function<double(Plus, double, double)> f6 = &Plus::plusd;//封装的是函数指针
function<double(Plus*, double, double)> f7 = &Plus::plusd;
//传的是对象 分为有名对象 匿名对象两种都可以传递
cout << f6(Plus(), 1.1, 1.1) << endl;
Plus pd;
cout << f7(&pd, 1.1, 1.1) << endl;
}
三:bind
调整参数顺序(不常用)
_1代表第一个实参
_2代表第二个实参
...
using placeholders::_1;
using placeholders::_2;
using placeholders::_3;
int Sub(int a, int b)
{
return (a - b) ;
}
int SubX(int a, int b, int c)
{
return (a - b - c) ;
}
int main()
{
auto a = bind(Sub, _1, _2);
cout << a(10, 20) << endl;
// 调整参数个数 (常用)
auto b = bind(Sub, 100, _1);//固定一个值 _1永远表示第一个你要传给的值,不是固定第一个
cout << b(20) << endl;;
auto c = bind(Sub, _1, 100);
cout << c(20) << endl;
auto d = bind(SubX, _1, _2, _3);
cout << d(10, 20, 30) << endl;
auto e = bind(SubX, 100, _1, _2);
cout << e(20, 30) << endl;
auto f = bind(SubX, _1, 100, _2);
cout << e(20, 30) << endl;
return 0;
}
最常用的就是用调整参数个数,还有就是调整参数顺序
_1 ,_2这种表示你开始传参(也就是除了那些固定的值的)的第一个,开始传参之后的第二个
还有就是要注意function 和bind不一样的区别,function要传有名对象,匿名对象或者有名对象的指针,bind传的函数指针并不用加括号,但是function在传匿名对象时候加了括号,注意括号的使用