C++:Function,Bind,Lambda:

1. Function (函数模板:实现函数对象的函数类型的保存):

可以使用Function 实现对函数的封装为function对象,并且灵活调用;

解决了函数对象lambda表达式、bind绑定器只能限制在当前语句使用的局限;

1.1. 函数对象类型:

string Hello()
{
	return "hello world";
}
int sum(int a, int b)
{
	return a + b;
}
class Yab
{
public:
	void Hello(string s)
	{
		cout<< s+s;
	}
};
string H(string s)
{
	return s;
}

//function:可以实现函数对象(:绑定器、函数对象、lambda表达式) 的类型保存,而不是只在单条语句才能执行

int main()
{
	//function(函数模板) 用函数类型实例化
	
	//1  用普通函数实例化function1
	function<string()>function1 = Hello;
	cout<<function1()<<endl;

	function<int(int, int)>function2=sum;
	cout << function2(11, 10)<<endl;

	//2 用类的成员函数实例化function
	//function<void(Yab*, string)>function3 = [](Yab* yab, string a)->void {
	//	cout << a + a;
	//};
	function<void(Yab*, string)>function3 = &Yab::Hello;
	Yab y;
	function3(&y, "hahahaha ");

	//3 用lambda表达式实例化function
	function<string(string, string)>function4 =
		[](string s1, string s2)->string {
		return s1 + s2;
	};
	cout << function4("lulu ", " fighting!");
	return 0;
}
function总结:
  1. function对象需要函数类型((函数返回类型(函数参数类型)实例化
  2. function类对象被调用后,即调用operator()( )对象括号的重载函数,第二个括号内为函数参数,在函数内部调用被封装的函数,
  3. 调用对象function(),()内写入函数类型参数一致的参数

1.2. function可以优化项目目录的问题:

在跳转执行函数的选择中,我们最常使用的switch(),违背开闭原则,而利用function直接绑定函数,用map封装function与之匹配的选项,在添加删除时更加安全

//这是配置好的模板文件
#include <iostream>
#include <string>
#include<functional>//包含所有函数对象
#include<algorithm>//包含所有泛型算法
#include<vector>
#include<ctime>
#include<map>
using namespace std;
using namespace placeholders;
void Show()
{
	cout << " 欢迎来到图书管理系统:\n";
	cout << "**********************\n";
	cout << "  1: 图书信息查询\n";
	cout << "  2: 图书信息修改\n";
	cout << "  3: 图书信息删除\n";
	cout << "  4: 图书信息新增\n";
	cout << "  5: 退出\n";
	cout << "**********************\n";
}
void Showbook1()
{
	cout << "  欢迎来到信息查询\n";
}
void Modefiybook2()
{
	cout << "  欢迎来到信息修改\n";
}
void Deletehbook3()
{
	cout << "  欢迎来到信息删除\n";
}
void Insertbook4()
{
	cout << "  欢迎来到信息新增\n";
}
void Mapinsert(map<int, function<void()>>Hmap)
{
	Hmap.insert({ 1, Showbook1 });
	Hmap.insert({ 2, Modefiybook2 });
	Hmap.insert({ 3, Deletehbook3 });
	Hmap.insert({ 4, Insertbook4 });
}
int main()
{
	Show();
	map<int, function<void()>>Hmap;//插入function 对象到map结合中
	Mapinsert(Hmap);
	int i = 0;
  //推荐方法1:
	//while (1)
	//{
	//	cin >> i;
	//	if (i == 5)
	//		break;
	//	auto it = Hmap.find( i);
	//	if ( it== Hmap.end())
	//	{
	//		cout << " 请输入有效选项";
	//	}
	//	else
	//	{
	//		it->second();
	//	}
	//}

//方法2:
	//违背了开闭原则,无异于维护修改
	/*while (i != 5)
	{
		cin >> i;
		switch(i)
		{
			case 1:  
				Showbook1();
				break;
			case 2:
				Modefiybook2();
				break;
			case 3:
				Deletehbook3();
				break;
			case 4:
				Insertbook4();
				break;

		};		
	}*/
	return 0;
}

2. function 的底层实现原理:

利用模板类实现函数对象,在小括号重载函数中调用功能函数

//!!!
template <typename FTY>
class myfunction{};

template<typename R,typename ...A>
class myfunction<R(A...)>
{
public:
	using PFUNC = R * (A...);
	myfunction(PFUNC _pfunc) :pfunc(_pfunc) {};
	R operator()(A ...arg)
	{
		return func(arg...);
	}
private:
	PFUNC pfunc;
};
//!!!
void Hello()
{
	cout << "hello world!";
}
double sum(float a, double b, float c, int d)
{
	return a + b * c - d;
}
int main()
{
	function<void()>fun = Hello;
	fun();
	//模板类中对于函数参数,改为可变参数的序列集合"A...arg",可包容各个函数的参数类型个数
	function<double(float, double, float, int)>fun2 = sum;
	cout<<fun2(1.22222222222,2.999999,3.22222,4.3333);
	return 0;
}

2. Bind(绑定器函数模板:实现对函数的绑定):

2.1. bind1st,bind2nd:

C++ STL 绑定器,将二元函数(两个参数的函数)

  • (bind1st)第一个参数 绑定为固定值,成为一元函数对象
  • (bind2nd) 第二个参数 绑定为固定值,成为一元函数对象
	sort(v.begin(), v.end(), greater<int>());
	//降序:
	//在第一个小于7的数据迭代器位置插入7
	//less<>: a<b  绑定第二个迭代器,成为一元函数对象
	// greater<>:a>b 绑定第一个迭代器:第一个小于七
	//find_if :一元函数对象
	auto it3 = find_if(v.begin(), v.end(), bind2nd(less<int>(), 7));
	auto it3 = find_if(v.begin(), v.end(), bind1st(greater<int>(), 7));

2.1.1. 自己的封装 bind1st , find_if:

#include <iostream>
#include <string>
#include<functional>//包含所有函数对象
#include<algorithm>//包含所有泛型算法
#include<vector>
#include<ctime>

using namespace std;


template<typename Iterator, typename Compare>
Iterator myfind_if(Iterator first, Iterator last, Compare comp)
{
	for (; first != last; first++)
	{
		if (comp(*first))
			break;
	}
	return first;
}


template<typename Compare,typename T>
class _mybind1st
{
public:
	_mybind1st(Compare comp, T val) :_comp(comp), _val(val) {};
	bool operator()(const T& a)
	{
		return _comp(_val,a);
	}
private:
	Compare _comp;
	T _val;
};

template<typename Compare, typename T>
_mybind1st<Compare, T> mybind1st(Compare comp, const T val)
{
	return _mybind1st<Compare, T>(comp, val);
}


template<typename Compare,typename T>
class _mybind2nd
{
private:
	T _val;
	Compare _comp;
public:
	_mybind2nd(Compare comp, T val) :_comp(comp), _val(val) {};
	bool operator()(const T& a)
	{
		return _comp(_val, a);
	}
};
template<typename Compare,typename T>
_mybind2nd<Compare, T> mybind2nd(Compare comp, const T& val)
{
	return _mybind2nd<Compare, T>(comp, val);
}
void Hello()
{
	cout << "hello world!";
}
double sum(float a, double b, float c, int d)
{
	return a + b * c - d;
}
int main()
{
	vector<int>v;
	for (int i = 0; i < 12; i++)
	{
		v.push_back(rand() % 11);
	}
	sort(v.begin(), v.end(), greater<int>());
	//插入6 a>b
	auto it = myfind_if(v.begin(), v.end(), mybind1st(greater<int>(), 6));
	if (it != v.end())
		v.insert(it,6);
	//插入10 a<b

	auto it2 = myfind_if(v.begin(), v.end(), mybind2nd(greater<int>(), 9));
	if (it2 != v.end())
		v.insert(it2, 9);
	for (auto it : v)
	{
		cout << it << " ";
	}
	return 0;
}

2.1.2. bind 的应用举例:

//bind绑定器的参数占位符:placeholders
using namespace placeholders;

int sum(int a, int b)
{
	return a + b;
}
void hello(string s)
{
	cout << s;
}
class Ba
{
public:
	int sum(int a, int b)
	{
		return a + b;
	}
};
int main()
{
	cout<<bind(sum,10, 20)() << endl;
	bind(hello, placeholders::_1)("hello 2024");
	cout<< endl;
	cout << bind(&Ba::sum, Ba(), 30, 30)()<<endl;
	return 0;
  }
2.1.2.1. 结合function 则可以将bind器的函数结构保存,并不断复用
//bind()绑定器将函数对象的执行只局限与绑定的当前语句内,而结合function 则可以将bind器的函数结构保存,并不断复用

  //bind绑定器的参数占位符:placeholders
  using namespace placeholders;
  function<void(string)>fun1 = bind(hello, _1);
	function<int(int, int)>fun2 = bind(sum, _1, _2);
	function<int(int, int)>fun3 = bind(&Ba::sum, Ba(), _1, _2);

	fun1("hello  ");
	fun1("2024  and  ");
	fun1("2002  ");
	cout << endl;

	cout << fun2(1, 2) << "    ";
	cout << fun2(10, 20)<< "    ";
	cout << fun2(100, 200)<<endl;

	cout << fun3(1, 2) << "    ";
	cout << fun3(10, 20) << "    ";
	cout << fun3(100, 200) << endl;

2.1.3. bind 结合function 实现线程池

#include <iostream>
#include <string>
#include<functional>//包含所有函数对象
#include<algorithm>//包含所有泛型算法
#include<vector>
#include<ctime>
#include<thread>
using namespace std;

//线程池:
class Thread
{
public:
	Thread(function<void()>func) :_func(func) {};
	thread start()
	{
		return thread(_func);
	}
private:
	function<void()>_func;
};

class Threadpool
{
public:
	Threadpool() {};
	~Threadpool() {
		for (int i = 0; i < _pool.size(); i++)
		{
			delete _pool[i];
		}
	};
	//开启线程池(size:线程池中的线程数量)
	void startpool(int size)
	{
		for (int i = 0; i < size; i++)
		{
			_pool.push_back(new Thread(
				bind(&Threadpool::runThread, this, i)));
		}
		for (int i = 0; i < size; i++)
		{
			_handler.push_back(_pool[i]->start());
		}
		for (thread& t : _handler)
		{
			t.join();
		}
	}

private:
	vector<Thread*>_pool;
	vector<thread>_handler;//句柄
	//线程函数
	void runThread(int id)
	{
		cout << "call runThread ! id: " << id << endl;
	}
};

int main()
{
	Threadpool pool;
	pool.startpool(10);
	return 0;
}

3. Lambda(构造函数对象):

在泛型算法、自定义函数比较、优先级队列中,对于函数对象的优化以及简化构建,避免代码中出现大量仅重载小括号的类

3.1.1. 格式:

[ 捕获外部变量 ] ( 参数列表 ) -> 函数返回值类型 {

实现代码...
};

3.1.1.1. 外部变量捕获方式:

[ ]:默认不捕获任何变量

[&] :引用 , [*] :指针 , [=] :值 , [this] : 捕获this指针对象

[=a,&b] : 值捕获a ,引用捕获 b ...

3.1.1.2. 注意:
  1. 若函数返回值类型为void,可以省略 ->及类型
  2. [=] ,值捕获的变量在第一次捕获入lambda表达式内以后,不再改变,即使函数外捕获变量的值改变,lambda表达式内的值依然为首次捕获

eg:

	int a = 10, b = 20;
	auto fun1=[=]() {cout << a + b<<endl;};
	//lambda 表达式的值捕获,只保存第一次进入lambda表达式捕获的值,后面有修改也不会改变内部的值
	fun1();   a = 20;   fun1();

3.1.2. lambda的实现与应用

lambda表达式作为函数对象只限制在语句内使用,若想实现已经定义好的lambda类型,需要结合function<>(已经确定的lambda函数类型实例化),并在实例化对象的同时实现lambda函数,在之后则可以直接使用

3.1.2.1. 实现在优先级队列中的自定义比较函数
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string>
#include<vector>
#include<algorithm>
#include<queue>
#include<map>
#include<functional>

using namespace std; 
class Data
{
private:
public:	
	int a1;
	int b1;


	Data(int a, int b) :a1(a), b1(b) {};
	//方法一:不够灵活,在参数和比较方式增多时,在类中重载比较方式显得尤为笨重
	//bool operator>(const Data& data)const { return a1 > data.a1; };
	//bool operator<(const Data& data)const { return a1 < data.a1; };
	void Show()const { cout << a1 << "   " << b1 << endl; };
};
int main()
{
	//priority_queue<Data>data;

	//方法二:
	using func = function<bool(Data&,Data&)> ;
	using Pri_que=priority_queue<Data, vector<Data>, func>;
	Pri_que data ([](Data& data1,Data& data2)->bool {
		return data1.a1 > data2.a1;
		});

	for(int i=0;i<10;i++)
	data.push(Data(10+i*5, 20));

	while (!data.empty())
	{
		data.top().Show(); // 直接调用 Show 方法  
		data.pop(); // 不要忘记弹出元素,否则会导致无限循环  
	}


}
3.1.2.2. 实现智能文件指针的自定义删除器
//use _CRT_SECURE_NO_WARNINGS.See online help for details.Project5	D : \小徐同学\练习\Project5\lambda.cpp	60

	using Ptr = unique_ptr<FILE, function<void(FILE*)>>;
	Ptr p1(fopen("data.txt", "rb"), [](FILE* pf) {fclose(pf); });
	//拥有自定义删除器的文件指针
3.1.2.3. 实现map 的调用方法:
vector<int>v;
	for (int i = 0; i < 10; i++)
	{
		v.push_back(rand() % 11);
		cout << v[i]<<" ";
	}
	sort(v.begin(), v.end(), [](int c,int d)->bool {
		return c<d;
		});

	cout << endl << endl;
	map<int, function<int(int, int)>>map;
	map[0] = [](int a, int b)->int {return a + b; };
	map[1] = [](int a, int b)->int {return a - b; };
	map[2] = [](int a, int b)->int {return a * b; };
	map[3] = [](int a, int b)->int {return a / b; };

	for(int i=0;i<4;i++)
	cout << map[i](1, 2)<<endl;

  • 22
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值