C++11 的继续学习

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写 ,比较方便用于多个不同种类的那种,有利之处类似于多态那种感觉。
lambda表达式书写格式:[capture-list] (parameters) mutable -> return-type { statement
}

  1. lambda表达式各部分说明

capture-list\] : **捕捉列表** ,该列表总是出现在lambda函数的开始位置,**编译器根据\[\]来** **判断接下来的代码是否为lambda函数** ,**捕捉列表能够捕捉上下文中的变量供lambda** **函数使用**。 (parameters):参数列表。与**普通函数的参数列表一致**,如果不需要参数传递,则可以 连同()一起省略 mutable:默认情况下,lambda函数总是一个const函数,mutable可以取消其常量 性。使用该修饰符时,参数列表不可省略(即使参数为空)。 **-\>returntype:返回值类型** 。用**追踪返回类型形式声明函数的返回值类型**,没有返回 值时此部分可省略。**返回值类型明确情况下,也可省略,由编译器对返回类型进行推** **导**。 **{statement}:函数体**。在该函数体内,除了可以使用其参数外,还可以使用所有捕获 到的变量。 **注意:** 在lambda函数定义中,**参数列表和返回值类型都是可选部分,而捕捉列表和函数体可以为** **空** 。因此C++11中**最简单的lambda函数为:\[\]{}**; 该lambda函数不能做任何事情。 int main() { vector 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; } ![](https://i-blog.csdnimg.cn/direct/0195af3d176042a79f46a0c605c815a7.png) 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)<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; } 3捕获列表说明 **捕捉列表描述了上下文中那些数据可以被lambda使用** ,以及**使用的方式传值还是传引用**。 \[var\]:表示值传递方式捕捉变量var \[=\]:表示值传递方式捕获所有父作用域中的变量(包括this) \[\&var\]:表示引用传递捕捉变量var \[\&\]:表示引用传递捕捉所有父作用域中的变量(包括this) \[this\]:表示值传递方式捕捉当前的this指针 注意: a. **父作用域指包含lambda函数的语句块** b. **语法上捕捉列表可由多个捕捉项组成,并以逗号分割**。 比如:\[=, \&a, \&b\]:以引用传递的方式捕捉变量a和b,值传递方式捕捉其他所有变量 \[\&,a, this\]:值传递方式捕捉变量a和this,引用方式捕捉其他变量 c. **捕捉列表不允许变量重复传递,否则就会导致编译错误**。 比如:\[=, a\]:=已经以值传递方式捕捉了所有变量,捕捉a重复 d. **在块作用域以外的lambda函数捕捉列表必须为空**。 e. 在块作用域中的lambda函数仅能捕捉父作用域中局部变量,捕捉任何非此作用域或者 非局部变量都 会导致编译报错。 f. **lambda表达式之间不能相互赋值**,即使看起来类型相同 4:lambda与 函数对象(仿函数) 仿函数: 在类中重载了operator()运算符的类对象。 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包装器** function包装器 也叫作适配器。C++中的function本质是一个类模板,也是一个包装器。 #include 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 f1 = f; functionf2 = Functor(); function f3 = [](int x, int y) {return x + y; }; } 让我们以一道题看看function 的作用:[LCR 036. 逆波兰表达式求值 - 力扣(LeetCode)](https://leetcode.cn/problems/8Zf90G/ "LCR 036. 逆波兰表达式求值 - 力扣(LeetCode)") class Solution { public: int evalRPN(vector& tokens) { stack st; map> 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 f6 = &Plus::plusd;//封装的是函数指针 function f7 = &Plus::plusd; //传的是对象 分为有名对象 匿名对象两种都可以传递 cout << f6(Plus(), 1.1, 1.1) << endl; Plus pd; cout << f7(&pd, 1.1, 1.1) << endl; } 三:bind std::bind函数定义在头文件中,**是一个函数模板,它就像一个函数包装器(适配器)** ,**接受一个可** **调用对象(callable object),生成一个新的可调用对象来"适应"原对象的参数列表**。一般而 言,我们用它可以把一个原本接收N个参数的函数fn,通过绑定一些参数,返回一个接收M个(M 可以大于N,但这么做没什么意义)参数的新函数。同时,使用std::bind函数还可以实现参数顺 序调整等操作。 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; } 最常用的就是用调整参数个数,还有就是调整参数顺序 ![](https://i-blog.csdnimg.cn/direct/3511532b832e4a489d6cf7cd0d85c082.png) **_1 ,_2这种表示你开始传参(也就是除了那些固定的值的)的第一个,开始传参之后的第二个** **还有就是要注意function 和bind不一样的区别,function要传有名对象,匿名对象或者有名对象的指针,bind传的函数指针并不用加括号,但是function在传匿名对象时候加了括号,注意括号的使用**

相关推荐
小脑斧爱吃鱼鱼28 分钟前
鸿蒙项目笔记(1)
笔记·学习·harmonyos
阿linlin29 分钟前
OpenCV--图像预处理学习01
opencv·学习·计算机视觉
车载小杜35 分钟前
基于指针的线程池
开发语言·c++
张张张3121 小时前
4.2学习总结 Java:list系列集合
java·学习
SuperW2 小时前
linux课程学习二——缓存
学习
杉之3 小时前
SpringBlade 数据库字段的自动填充
java·笔记·学习·spring·tomcat
云 无 心 以 出 岫3 小时前
贪心算法QwQ
数据结构·c++·算法·贪心算法
换一颗红豆3 小时前
【C++ 多态】—— 礼器九鼎,釉下乾坤,多态中的 “风水寻龙诀“
c++
随便昵称4 小时前
蓝桥杯专项复习——前缀和和差分
c++·算法·前缀和·蓝桥杯
commonbelive4 小时前
团体程序设计天梯赛——L1-100 四项全能
c++