博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
std::function和std::bind绑定器
阅读量:3575 次
发布时间:2019-05-20

本文共 5761 字,大约阅读时间需要 19 分钟。

C++11中std::function and std::bind

1. 可调用对象

C++中可调用对象的概念,有以下几种定义:

1) 是一个函数指针
2) 是一个具有operator()成员函数的类对象
3) 是一个可被转换为函数指针的类对象
4) 是一个类成员(函数)指针

void fun(void){	//...}struct Foo{	void operator()(void){		//...	}};struct Bar{	using fr_t = void (*)(void);	static void fun(){		//...	}	operator fr_t(void){		return fun;	}};struct A{	int _a;	void mem_func(void){		//... 	}};int main(){	using FUN = void (*func_ptr)(void) ;  // 1.函数指针	FUN func_ptr = fun;	func_ptr();		Foo foo;	foo();                             // 2.仿函数	Bar bar;      	bar();                             // 3.可被转换为函数指针的类对象  		void(A::*mem_func_ptr)(void)       // 4.类成员函数指针		= &A::mem_func;	int A::*mem_obj_ptr                // 类成员指针		= &A::_a;	A aa;	(aa.*mem_func_ptr)();	aa,.*mem_ob_ptr = 123;}

上述(func_ptr,foo,bar,mem_func_ptr,mem_obj_ptr)都被称作可调用对象。上述的可调用对象并没有函数类型或者函数引用类型(只有函数指针),这是因为函数类型不能直接用来做定义对象,而函数引用更像const函数指针。

2. 可调用对象包装器std::function

std::function是可调用对象的包装器,它是一个类模板,可以容纳除了类成员(函数)指针之外的所有可调用对象。通过指定它的模板参数,它可以用统一的方式处理函数,函数对象,函数指针,并允许保存和延迟执它们。

2.1 std::function的基本用法

#include 
#include
void func(){ std::cout <<__FUNCTION__<< std::endl;}class Foo{ public: static int foo_func(int a){ std::cout << __FUNCTION__ << "(" << a << ") ->:\n"; return a; }};class Bar{ public: int operator()(int a){ std::cout << __FUNCTION__ <<"("<< a <<") ->\n"; return a; }};int main(){ std::function
fr1 = func; //绑定普通函数 fr1(); std::function
fr2 = Foo::foo_func; //绑定类静态成员函数 fr2(123); Bar bar; std::function
fr3 = bar; //绑定一个仿函数 fr3(321);}

从上述看到std::function的使用方法,当我们给std::function填入一个合适的函数签名(即一个函数类型,只需要返回值和参数表)之后,它就可以变成了一个容纳所有这类函数方式的”函数包装器“。

2.2 std::function作为回调

class A{    std::function
callback; public: A(const std::function
& f):callback(f){} void notify(){ callback();//回调到上层 }};class Foo{ public: void operator()(void){ std::cout <<__FUNCTION__<<"is executable"<< std::endl; }};int main(){ Foo foo; A aa(foo); aa.notify();}

从上面的例子中可以看到,std::function可以取代函数指针的作用。因为它可以保存函数延迟执行,所以适合做回调函数。

typedef void( *Func)(void);using Func = void(*)(void);

使用函数指针类型作为成员也可以完成,但是回调函数只能是普通函数而不能是仿函数等(需要再次转型)。

2.3 std::function作为函数入参

void call_when_even(int x,const std::function
& f){ if(!(x & 1)){ f(x); } else{ std::cout <<"并未触发回调:"<
<< std::endl; }}void output(int x){ std::cout <<__FUNCTION__<<" parament value : "<
<< std::endl;}int main(){ int num = 10; while(num--) call_when_even(num,output);}

从上述例子可以看出,std::function比函数指针更加灵活。

3. std::bind绑定器

std::bind用来可将于可调用对象与其参数一起绑定,绑定后的结果使用std::function进行保存,并延迟到任何我们需要的时候。

通俗讲,它有两大作用:
1)将可调用对象与其参数一起绑定为一个仿函数。
2)将多元(参数n,n>1)可调用对象转化成一元或者(n-1)元可调用对象,即只绑定部分参数。

3.1 std::bind基本用法

#include 
#include
void output(int x,int y){ std::cout <<__FUNCTION__<
<<","<
<< std::endl;}int main(){ std::bind(output,1,2)(); //输出:1,2 std::bind(output,std::placeholders::_1,2)(11); //输出:11,2 std::bind(output,2,std::placeholders::_1)(111);//输出:2,111 //std::bind(output,std::placeholders::_1,std::placeholders::_2)(1); //error std::bind(output,std::placeholders::_1,std::placeholders::_2)(100,1000);}

从上述可得对std::bind的返回结果直接调用。可以看到,std::bind可以绑定所有参数,也可以仅仅绑定部分参数。

3.2 std::function和std::bind配合使用

class A{    public:    int i_ = 100;    void output(int x,int y){        std::cout <<__FUNCTION__<<":"<
<<","<
<< std::endl; }};int main(){ A a; std::cout <
<< std::endl; std::function
fr = std::bind(&A::output,&a,std::placeholders::_1,std::placeholders::_2); fr(1,2); std::function
fr_i = std::bind(&A::i_,&a); fr_i() = 123; std::cout <
<< std::endl;}

通过std::function和std::bind的配合,对所有可调用对象均有了统一调用方法。

3.3 std::bind1st,std::bind2nd,std::bind

//查找元素大于10的元素个数int count = std::count_if(cool.begin(),cool.end(),std::bind1st(std::less
(),10);//等与上式子int count = std::count_if(cool.begin(),cool.end(),std::bind2nd(std::greater
(),10));//查找元素小于10的元素个数int count = std::count_if(cool.begin(),cool.end(),std::bind1st(std::greater
(),10));//等于上式子int count = std::count_if(cool.begin(),cool.end(),std::bind2nd(std::less
(),10));//查找元素大于10的元素个数using std::placeholders::_1;int count = std::count_if(cool.begin(),cool.end(),std::bind(std::less
(),10,_1));//查找元素小于10的元素个数int count = std::count_if(cool.begin(),cool.end(),std::bind(std::less
,_1,10));

std::placeholders 占位符合理使用,就不要纠结使用bind1st还是bind2nd。

3.4 使用std::bind组合函数

//判断大于5小于10的元素(左开右闭)auto f = std::bind(std::logical_and
(), std::bind(std::greater
(),std::placeholders::_1,5), std::bind(std::less_equal
(),std::placeholders::_1,10));int count = std::count_if(cool.begin(),cool.end(),f);

3.5 使用std::bind和std::function进行黑盒测试

typedef std::function
REC; //回调函数类型Type func(int ,int,REC);

在某个类中存在函数func,需要参数int,int,REC。于是在调用时可能如下:

bool awk(cosnt char *str,int b);func(10,10,awk);

但实际这样的函数在进行测试不能解决问题(需要重载或者修改原函数接口,而这么做不符合软件的开闭原则),因而需要使用lambda或者std::bind或者函数对象。

//std::bindbool sawk(std::string &s,const char* str,int b);std::string s;auto t1 = std::bind(sawk,std::ref(s),std::placeholders::_1,std::placeholders::_2);func(2,1,t1);// lambdastd::string s;auto t2 = [&s](const char*,int b)->bool {return true;};func(2,1,t2);//function objectclass TS{public:     bool operator()(const char *str,int a);private:    std::string d;};TS t3;func(2,1,std::ref(t3));

通过传入std::bind绑定的函数,lambda,以及仿函数得到的函数符合传入REC的类型,但是可以额外附带的参数可以完成测试功能。

转载地址:http://ocxgj.baihongyu.com/

你可能感兴趣的文章
使用docker搭建YAPI服务
查看>>
西南科技大学OJ题 邻接表到邻接矩阵1056
查看>>
西南科技大学OJ题 有向图的出度计算1057
查看>>
西南科技大学OJ题 有向图的最大出度计算1059
查看>>
西南科技大学OJ题 带权有向图计算1063
查看>>
oracle主键自增触发器编写
查看>>
String与StringBuilder与StringBuffer三者的差别
查看>>
各种IO流之间的关系和区别
查看>>
SSM如何实现上传单图片
查看>>
SSM环境下java如何实现语音识别(百度语音识别版)
查看>>
ajax方法参数的用法和他的含义
查看>>
数据库基础技巧及用法
查看>>
实用方法:无request参数时获得当前的request的方法
查看>>
JS操作数组常用实用方法
查看>>
springboot实现CAS的server服务器端的搭建,并实现链接mysql数据库,自定义加密算法
查看>>
Python超详细的安装教程
查看>>
小甲鱼Python第一讲(我和Python的第一次亲密接触)
查看>>
小甲鱼Python第三讲(小插曲之变量和字符串)
查看>>
小甲鱼Python第十一讲(一个打了激素的数组2)
查看>>
小甲鱼Python第十三讲(戴上了枷锁的列表)
查看>>