目录

一,lambda表达式

1.lambda表达式简介

2 lambda表达式的五个部分

3.lambda表达式的使用

4.lambda表达式的类型

5,lambda表达式的本质

二,function包装器

 1,function简介

2.为什么要包装可调用对象

3.使用

三,bind绑定器


一,lambda表达式

1.lambda表达式简介

lambda表达式书写格式如下

2 lambda表达式的五个部分

1.捕捉列表capturelist[ ]  这个部分是lambda表达式不可缺少的一个部分,也正是这一部分我们的lambda表达式成为了lambda表达式

2.参数parameters这个部分是lambda表达式中可要可不要的一个部分

3.mutable这个东西相当于一个关键字,因为lambda表达式的参数属性默认const的,使用这个mutable能够解除掉lambda表达式的const属性

4.返回值returntype:这个部分也是可写可不写的,因为lambda表达式可以自动推导返回值类型

5.函数statement一定得写。   

 所以最简单的lambda表达式为:[]{};

3.lambda表达式的使用

对于lambda表达式的捕捉列表如下的使用方式

1.[val]:直接捕捉变量直接传入变量名方式

2.[&val]:引用方式捕捉。

3.[=]:传值方式捕捉所有在lambda父作用域内的变量

4.[&]:以传引用方式捕捉所有作用域内的变量

5.[this]:捕捉this指针,主要用于里面

示例

1,

//1,[val]传值方式
int main()
{
	int i = 0, j = 0;
	cout << "adress:" << &amp;i << " " << &amp;j << endl<<endl;

	auto f1 = [i, j] {cout << "adress:" << &amp;i << " " << &amp;j << endl << endl;};
	f1();
	return 0;
}

//

结果:两者的地址不一样,所以是传值,是一种拷贝行为

adress:006FF904 006FF8F8

adress:006FF8E8 006FF8EC

2,

//1,[&amp;val]传引用方式
int main()
{
	int i = 0, j = 0;
	cout << "adress:" << &amp;i << " " << &amp;j << endl<<endl;

	auto f1 = [&amp;i, &amp;j] {cout << "adress:" << &amp;i << " " << &amp;j << endl << endl;};
	f1();
	return 0;
}

//

结果:两者地址相同,所以是传引用

adress:00BAFA08 00BAF9FC

adress:00BAFA08 00BAF9FC

当然,这两者还可以搭配起来使用变成:auto f1 = [i, &amp;j] {cout << “adress:” << &i << ” ” << &j << endl << endl;};这样的话,第一个i便是传值,第二个j便是传应用

3,

//直接以传值的方式捕捉父作用域变量 [=]
int main()
{
	int i = 0, j = 0;
	cout << "adress:" << &i << " " << &j << endl<<endl;

	auto f1 = [=] {cout << "adress:" << &i << " " << &j << endl << endl;};
	f1();
	return 0;
}

结果

adress:00F8FD8C 00F8FD80

adress:00F8FD70 00F8FD74

4,

//以传引用方式捕捉所有变量[&]
int main()
{
	int i = 0, j = 0;
	cout << "adress:" << &i << " " << &j << endl<<endl;

	auto f1 = [&] {cout << "adress:" << &i << " " << &j << endl << endl;};
	f1();
	return 0;
}

结果

adress:00B9F9D8 00B9F9CC

adress:00B9F9D8 00B9F9CC

5,

五种方式便是捕捉this指针this指针在哪里呢?在类里面。所以捕捉this指针的使用场景便是在类里面使用的。

对于如下场景直接捕捉变量是行不通的:

class A {
public:
	void func()
	{
		auto f2 = [a1,a2] {cout << "a1:" << a1 << " " << "a2:" << " " << a2;};
	}

private:
	int a1 = 1;
	int a2 = 2;
};

原因在于lambda表达式的父作用域func函数体,a1,a2不在这个作用域里面。在这个时候就得使用捕捉this指针的方式解决问题了:

class A {
  public:
	void func()
	{
		auto f2 = [this] {cout << "a1:" << a1 << " " << "a2:" << " " << a2;};
	}

private:
	int a1 = 1;
	int a2 = 2;
};

使用:

class A {
public:
	void func()
	{
		auto f2 = [this] {cout << "a1:" << a1 << " " << "a2:" << " " << a2;};
		f2();
	}

private:
	int a1 = 1;
	int a2 = 2;
};


int main()
{
	A a;
	a.func();
	return 0;
}

结果

a1:1 a2: 2

能用this指针原因在于,this指针其实是类函数一个默认参数。 

4.lambda表达式的类型

使用typeid(函数名/变量名).name()便可以知道一个lambda表达式的类型实验如下

int main()
{
	auto f1 = [] {};
	auto f2 = [] {};

	cout << typeid(f1).name() << endl << endl;
	cout << typeid(f2).name() << endl << endl;

	return 0;
}

得到的结果如下

class <lambda_d4e7b29f43988cb7e0ced57656dd48f2&gt;

class <lambda_5e6719a5fcb7a4e6979dcea7af21cec0>

可以看到两个lambda表达式的类型都是奇怪的东西,都是一个class加上一个lambda+一串数字。这串数字其实是一个UUID。UUID是啥呢?百度如下

这个UUID表示的是一个唯一通识码。其实在查完以后我还是对此并不了解,但是我可以告诉你在lambda表达式里面如果这两个lambda表达式的UUID不一样,那这两个lambda表达式的类型也是不一样的。所以因为类型不同,于是f1和f2也是不可以相互赋值的。(不同的lambda表达式不能相互赋值如果赋值便会报错

5,lambda表达式的本质

lambzda表达式的本质其实就是一个仿函数。何以见得呢?这两个万一完全不一样啊?仿函数是在一个类里面实现一个operator(),但是lambda表达式却是一个[]{}的表达式,这两个看起来毫不相干的东西怎么能使一个玩意呢?在这个时候就要透过现象看本质了,拉出汇编代码

struct com//仿函数
{
public:
	bool operator()(int a,int b)
	{
		return a > b;
	}
};

int main()
{
	int i = 0, j = 1;
	auto f1 = [i, j](int i,int j) {return i > j;};
	f1(i, j);//调用lambda表达式

	com Com;
	Com(i, j);//调用仿函数
	return 0;
}

现在来查看一下汇编代码

仿函数:

lambda表达式:

从lambda表达式和仿函数的汇编代码比较可以看出这这两个毫不相干的的两个东西其实底层是一样的!!!

二,function包装

 1,function简介

这里介绍一下function包装器的,首先function包装器是定义头文件functional内的。function包装器是用来包装调用对象的。这里的可调用对象包括:

1.函数指针  2.仿函数  3.lambda表达式。

2.为什么包装调用对象

这三个可调用对象其实各有自己的缺点:

1.函数指针反人类void(*comback)()

2.仿函数太重了:在使用仿函数时还需要专门去写一个类来对仿函数进行调用

3.lambda表达式的类型确定,难以调用

因为以上的·缺点,导致这三个可调用对象难以调用。所以function包装器应运而生!!!

3.使用

包装器的使用:function<return_type(Parameter type)>

当可调用对象返回值参数可以匹配时便可以包装成功

使用场景如下:

1.逆波兰表达式的普通写法

class Solution {
public:
    int evalRPN(vector<string>& tokens) {

        stack<int>st;

        for(int i = 0;i<tokens.size();i++)
        {
         

            if(tokens[i]=="+"||tokens[i]=="-"||tokens[i]=="*"||tokens[i]=="/")
            {

                int right = st.top();
                st.pop();
                int left = st.top();
                st.pop();
                if(tokens[i]=="+")
                {
                    st.push(left+right);
                }

                if(tokens[i]=="-")
                {
                    st.push(left-right);
                }

                if(tokens[i]=="*")
                {
                    st.push(left*right);
                }
                
                if(tokens[i]=="/")
                {
                    st.push(left/right);
                }
            }
            else
            {
                st.push(stoi(tokens[i]));
            }
        }

        return st.top();

    }
};
控制台

2.加入function包装器后的改进版本

class Solution {
public:
    int evalRPN(vector<string>& tokens) {
        stack<int> st;
        map<string, function<int(int, int)>> hash = 
        {
            {"+", [](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(hash.count(e) == 0)
            {
                st.push(stoi(e));
            }
            else
            {
                int right = st.top();
                st.pop();
                int left = st.top();
                st.pop();
                st.push(hash[e](left, right));
            }
        }
        return st.top();
    }
};
 

三,bind绑定

bind绑定器的作用两个,一个是调整参数顺序,一个是调整参数的个数。在这两个作用中,其实有用的是第二个接下来看看代码实例

1.调换参数顺序

int Sub(int x, int y)
{
	return x - y;
}

int main()
{
	function<int(int, int)> f1 = bind(Sub,placeholders::_2, placeholders::_1);//传入的第一个参数给第二位,第二个参数给第一位
	cout<<f1(10, 5)<<endl<<endl;

	return 0;
}

结果

-5

2.减少调用参数

成员函数内有this*类型的参数,每次传参时为了匹配类型都要传入this*类型的参数。为了减少这种操作便可以将plus()绑死减少传参时的麻烦!!!

class Plus
{
	public:
	int Add(int x, int y)
	{
		return x + y;
	}
};

int main()
{
  function<int(int, int)> f2 = bind(&Plus::Add,Plus(), placeholders::_1, placeholders::_2);
  cout << f2(1, 5) << endl;

  return 0;

}

 

 

原文地址:https://blog.csdn.net/qq_41934502/article/details/134782934

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任

如若转载,请注明出处:http://www.7code.cn/show_49228.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱suwngjj01@126.com进行投诉反馈,一经查实,立即删除

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注