C++绑定器和函数对象

C++11中引入的bind绑定器和函数对象

知识点

  1. C++ STL中的绑定器
  • bind1st:operator()的第一个形参变量绑定成一个确定的值

  • bind2nd:operator()的第二个形参变量绑定成一个确定的值

  • 目前使用bind

  1. C++11从Boost库中引入了bind绑定器和function函数对象机制

  2. lambda表达式,底层依赖函数对象的机制实现

应用实例:

#include <iostream>
#include <vector>
#include <functional>
#include <algorithm>
using namespace std;

template<class Container>
void showContainer(Container &con){
    auto it = con.begin();
    for(; it != con.end(); ++it){
        cout << *it <<" ";
    }
    cout << endl;
}
int main(int argc, const char * argv[]) {
    vector<int> vec;
    srand(time(nullptr));
    for(int i=0; i<20; ++i){
        vec.push_back( rand() % 100 + 1);
    }
    showContainer(vec);
    sort(vec.begin(), vec.end());//默认是<
    showContainer(vec);
    //greater二元函数对象
    sort(vec.begin(), vec.end(), greater<int>());//>
    showContainer(vec);

    /*
    把70按顺序插入到vec容器中,找第一个小于70的数字
    operator()(const T &val)
    greater   a > b
    less      a < b
    绑定器+二元函数对象 =》一元函数对象
    bind1st: + greater bool operator()(70, const _Ty& _Right)
    bind2nd: + less bool operator()(const _Ty& _Left, 70)
    bind:   placeholders::_1是占位符
    */
    auto it1 = find_if(vec.begin(), vec.end(), bind(greater<int>(), 70, placeholders::_1));

    if( it1 != vec.end()){
        vec.insert(it1, 70);
    }
    showContainer(vec);
    return 0;
  • bind绑定器返回的结果还是一个函数对象

  • bind是函数模板,可以自动推演模板类型参数

  • bind只能在语句中,出了语句不能使用

  • bind可以使用参数占位符placeholders::_1

void hello(string str){
    cout << str << endl;
}
int sum(int a, int b){
    return a+b;
}
int main(){
    bind(hello, "hello bind!")();//hello bind!
    bind(hello, placeholders::_1)("hello bind!");//hello bind!
    cout << bind(sum, 10, 20)() << endl;//30
    return 0;
}

function函数对象类型的应用

  • 绑定器、函数对象、lambda表达式,他们只能使用在一条语句中,作用:保留这三类的类型

  • 用函数类型实例化function

  • function调用operator()函数的时候,需要根据函数类型传入相应的参数

void func1() {cout << "hello weiwei" << endl;}

void func2(string str){ //void(*pFUNC)(string)
	cout << str << endl;
}

int add(int a, int b){return a+b;}

class Test{
public://成员函数必须依赖对象,void(Test::*pFUNC)(string)
	void func3(string str) {cout << str << endl;}
};

int main(){
	//从function类模板定义template<class _Fty>要用一个函数类型实例化function
	function<void()> FUNC1 = func1;
	FUNC1();//func1.operator()

	function<void(string)> FUNC2 = func2;
	FUNC2("func2(string str)");//func2.opeartor()(string str)

	function<int(int, int)> FUNC3 = add;
	cout << FUNC3(3, 5) << endl;

	//operator()
	function<int(int, int)> FUNC4 = [](int a, int b)->int {return a+b;};
	cout << FUNC4(30, 50) << endl;

	//调用类成员函数
	function<void(Test*, string)> FUNC5 = &Test::func3;
	FUNC5(&Test(), "call Test::func3");
	return 0;
}
  • 菜单设计案例
void choiceNew()	{cout << "New" << endl;}
void choiceOpen()	{cout << "Open" << endl;}
void choiceSave()	{cout << "Save" << endl;}
void choiceClose()	{cout << "Close" << endl;}
int main(){
	int choice = 0;
	map<int, function<void()> > choiceMap;
	choiceMap.insert(make_pair(1, choiceNew));
	choiceMap.insert(make_pair(2, choiceOpen));
	choiceMap.insert(make_pair(3, choiceSave));
	choiceMap.insert(make_pair(4, choiceClose));
	for(;;){
		cout << "***************" << endl;
		cout << "1.New" << endl;
		cout << "2.Open" << endl;
		cout << "3.Save" << endl;
		cout << "4.Close" << endl;
		cout << "***************" << endl;
		cout << "请选择:" << endl;
		cin >> choice;
		auto mit = choiceMap.find(choice);
		if(mit == choiceMap.end()){
			cout << "输入无效" << endl;
			break;
		}
		else{
			mit->second();
		}
	}

	return 0;
}

模板的完全特例化和部分特例化

  • 引入
template<typename T>
bool compare(T a, T b){
	cout << "template compare" << endl;
	return a > b;
}
template<>
bool compare<const char*>(const char *a, const char *b){
	cout << "compare<const char*>" << endl;
	return strcmp(a, b) > 0;
}
int main(){
	compare(10, 20);
	compare("aaa", "bbb");//T const char*
	return 0;
}
  • 完全特例化和部分特例化示例
template<typename T>
class Test{
public:
	Test(){cout << "call Test template" << endl;}
};
//对char *类型提供的完全特例化版本#1
template<>//特例化语法
class Test<char *>{
public:
	Test(){cout << "call Test<char *> template" << endl;}
};
//针对指针类型提供的部分特例化版本#2
template<typename Ty>
class Test<Ty *>{
public:
	Test(){cout << "call Test<Ty *> template" << endl;}
};
//针对函数指针(返回值,有两个形参变量)提供的部分特例化版本
template<typename R, typename A1, typename A2>
class Test<R(*)(A1, A2)>{
public:
	Test(){cout << "call Test<R(*)(A1, A2) template" << endl;}
};
//针对函数类型提供的部分特例化版本
template<typename R, typename A1, typename A2>
class Test<R(A1, A2)>{
public:
	Test(){ cout << "call Test<R(A1, A2) template" << endl;}
};

int main(){
	Test<int> test1;//call Test template
	Test<char*> test2;//call Test<char *> template
	Test<int*> test3;//call Test<Ty *> template
	Test<int(*)(int, int)> test4;//call Test<R(*)(A1, A2) template
	Test<int(int, int)> test5;//call Test<R(A1, A2) template

	return 0;
}

模板的实参推演

  • 概念:从函数实参来确定模板实参的过程。在模板实参推演过程中,编译器使用函数调用中的实参类型来寻找模板实参,用这些模板实参生成的函数版本与给定的函数调用最为匹配

  • 示例

template <typename T>//T包含了所有大的类型
void func1(T a){
	cout << typeid(T).name() << endl;
}
template <typename R, typename A1, typename A2>
void func2( R (*a)(A1, A2) ){
	cout << typeid(R).name() << endl;
	cout << typeid(A1).name() << endl;
	cout << typeid(A2).name() << endl;
};
template <typename R, typename T, typename A1, typename A2>
void func3( R (T::*a)(A1, A2)){
	cout << typeid(R).name() << endl;
	cout << typeid(T).name() << endl;
	cout << typeid(A1).name() << endl;
	cout << typeid(A2).name() << endl;
}
int add(int a, int b){return a+b;}
class Test{
public:
	int add(int a, int b){return a+b;}
};
int main(){
	func1(10);//int
	func1("aaa");//char const *
	func1(add);//int (__cdecl*)(int,int)
	func2(add);//int    int     int
	func1(&Test::add);//int (__thiscall Test::*)(int,int)
	func3(&Test::add);//int	  class Test	  int int
	
	return 0;
}

function函数对象实现的原理

template <typename R, typename... A>
class myFunction<R(A...)>{
public:
	//using pFUNC = R(*)(A);
	typedef R(*pFUNC)(A...);
	myFunction(pFUNC func) : _pfunc(func){}
	R operator()(A... arg){
		return _pfunc(arg...);
	}
private:
	pFUNC _pfunc;
};
void func1(string str) { cout << str << endl;}

int add(int a, int b) { return a+b;}

int main(){
	myFunction<void(string)> FUNC1(func1);
	FUNC1("weiwei");

	myFunction<int(int, int)> FUNC2(add);
	cout << FUNC2(10, 20) << endl;
	return 0;
}

bind和function应用

  • 线程池应用

lambda表达式

  • 函数对象的升级版

  • 函数对象的缺点:使用在泛型算法参数传递,比较和自定义操作

  • 如果表达式的返回值不需要,可以省略"->返回值"

  • 语法:

[捕获外部变量](形参列表)->返回值{操作代码};
[]不捕获任何外部变量
[=]以传值的方式捕获外部的所有变量
[&]以引用的方式捕获外部的所有变量
[this]捕获外部的this指针
[=, &a]以传值的方式捕获外部所有变量,但是a变量以引用的方式捕获
[a, b]以传值的方式捕获外部变量a和b
[a, &b]a以传值的方式捕获,b以引用的方式捕获
int main(){
	auto func1 = []()->void {cout << "weiwei" << endl;};
	func1();

    auto func2 = [](int a, int b)->int {return a + b;};
	cout << func2(3, 10) << endl;
    /*
    int a = 10;
	int b = 20;
	auto func3 = [=](){//不能在非可变 lambda 中修改按值捕获
		int tmp = a;
		a = b;
		b = tmp;
	};
    */
    int a = 10;
	int b = 20;
	auto func3 = [=]() mutable {
		int tmp = a;
		a = b;
		b = tmp;
	};
    int a = 10;
	int b = 20;
	auto func4 = [&](){//不需要mutable
		int tmp = a;
		a = b;
		b = tmp;
	};
	func4();
	cout << "a:" << a << "b:" << b << endl;//20, 10
	return 0;
}
  • lambda表达式应用
int main(){
vector<int> vec;
	for(int i = 0; i < 20; ++i){
		vec.push_back(rand()%100 + 1);
	}
	sort(vec.begin(), vec.end(), [](int a, int b)->bool{ return a > b;});
	for(int val : vec){
		cout << val << " ";
	}
	cout << endl;
	//将65按序插入到vec中
	auto it = find_if(vec.begin(), vec.end(), [](int a)->bool{ return a < 65;});
	vec.insert(it, 65);
	for(int val : vec){
		cout << val << " ";
	}
	cout << endl;

	for_each(vec.begin(), vec.end(), [](int a){
		if( a % 2 == 0){
			cout << a << " ";
		}
	});
	cout << endl;

	system("pause");
	return 0;
	return 0;
}
  • lambda表达式只能使用在语句中,如何跨语句调用之前定义好的表达式,用什么类型来表示lambda表达式

    • lambda表达式是函数对象,用function类型
int main(){
	map<int, function<int(int, int)>> myMap;
	myMap[1] = [](int a, int b)->int {return a + b;};
	myMap[2] = [](int a, int b)->int {return a - b;};
	myMap[3] = [](int a, int b)->int {return a * b;};
	myMap[4] = [](int a, int b)->int {return a / b;};
	
	cout << "2+3 = " << myMap[1](2, 3) << endl;
	cout << "2-3 = " << myMap[2](2, 3) << endl;
	cout << "2*3 = " << myMap[3](2, 3) << endl;
	cout << "2/3 = " << myMap[4](2, 3) << endl;

	return 0;
}
  • 智能指针自定义删除器
int main(){
	unique_ptr<FILE, function<void(FILE*)>> 
		pfile(fopen("data.txt", "w"), [](FILE *pf){fclose(pf);});

	return 0;
}
  • 优先队列
class Test{
public:
	Test(int data1 = 10, int data2 = 20) : ma(data1), mb(data2){}
	/*灵活性差
	bool operator<(const Test &that) const { return this->ma < that.ma;}
	bool operator>(const Test &that) const { return this->ma > that.ma;}
	*/
	int ma;
	int mb;
};
int main(){
	//priority_queue<Test> queue;
	typedef function<bool(Test&, Test&)> FUNC;
	priority_queue<Test, vector<Test>, FUNC> 
		LargeHeap([](Test &t1, Test &t2)->bool 
		{ 
			return t1.ma > t2.ma;
		});
	LargeHeap.push(Test(10, 20));
	LargeHeap.push(Test(15, 20));
	LargeHeap.push(Test(10, 15));

	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值