std::function and bind
可调用对象(Callable Object)
函数指针
具有operator()成员函数的类对象(仿函数)
可被转换为函数指针的类对象
类成员函数指针
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| void func(void) { std::cout<<"函数指针"<<std::endl; }
struct Foo{ void operator()(void){ std::cout<<"仿函数"<<std::endl; } };
struct Bar{ using fr_t = void(*)(void);
static void func(void){ std::cout<<"指向函数的类对象"<<std::endl; }
operator fr_t(){ return func; } };
struct A{ int a; void mem_func(void){ std::cout<<"成员函数"<<std::endl; } };
int main(){ void (*func_ptr)(void) = func; func_ptr();
Foo foo; foo();
Bar bar; bar();
void (A::*mem_func_ptr)(void) = A::mem_func; int A::*mem_obj_ptr = &A::a;
A aa;
(aa.*mem_func_ptr)();
aa.*mem_obj_ptr = 123; std::cout<<aa.a<<std::endl; }
|
可调用对象的包装器-std::function
简介
它是一个类模板,可以容纳类成员(函数)指针(需要用bind该函数将实际对象绑定)之外的所有可调用对象。通过指定他的模板参数,它可以统一的方式处理函数、函数对象、函数指针,并允许保存和延迟执行它们
弹性更强
- 对于函数对象的返回值可以进行适当隐式转换(short and float -> int)(兼容性)
- 对于函数对象的参数可以被隐式转换
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
| #include <iostream> #include <functional>
void func(){ std::cout<<__FUNCTION__<<std::endl; }
class Foo{ public: using f_int = int(*)(int); static int foo_func(int x){ std::cout<<__FUNCTION__<<std::endl; return x; } operator f_int () { return foo_func;} };
class Bar{ public: int operator()(int x){ std::cout<<__FUNCTION__<<std::endl; return x; } };
struct A{ int a; void mem_func(void){ std::cout<<__FUNCTION__<<std::endl; } };
void call_when_even(int x,const std::function<void(int)>& f) { if(!(x&1)) { f(x); } }
void output(int x) { std::cout<<x<<" "; }
void test_f(){ std::function<void(void)> fr1 = func; fr1();
std::function<int(int)> fr2 = Foo::foo_func; std::cout<<fr2(2)<<std::endl; std::function<int(int)> fr3 = Foo(); std::cout<<fr3(3)<<std::endl;
std::function<int(int)> fr4 = Bar(); std::cout<<fr4(4)<<std::endl;
std::cout<<"----bind and function---"<<std::endl; A a; auto bf1 = std::bind(&A::mem_func,&a); auto bp1 = std::bind(&A::a,a); bp1() = 123; std::cout<<bp1()<<std::endl; std::cout<<a.a<<std::endl; std::function<void(void)> fr5 = bf1; fr5(); }
int main(){ test_f(); for(int i = 0;i<10;++i){ call_when_even(i,output); } std::cout<<std::endl; return 0; }
|
std::bind绑定器
std::bind用来将可调用对象与其参数一起进行绑定,绑定后的结构可以使用std::function进行保存,并延迟调用到任何我们需要的时候
作用
将可调用对象与其参数一起帮定成一个仿函数
将多元参数可调用对象转成一元或者(n-1)元金额调用对象,及只绑定部分参数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
| #include <iostream> #include <functional> class FuncEntity{ public: int eFunc(int a){ return a; } };
void test_b(){ FuncEntity e; auto a = std::bind(&FuncEntity::eFunc,e,std::placeholders::_1);
std::cout<<a(2); }
void call_when_even(int x,const std::function<void(int)>& f) { if(!(x&1)) { f(x); } }
void output(int x) { std::cout<<x<<" "; } void output_add_2(int x) { std::cout<<x+2<<' '; }
int main(){ { auto fr = std::bind(output,std::placeholders::_1); for(int i=0;i<10;++i) { call_when_even(i,fr); } std::cout<<std::endl; } { auto fr = std::bind(output_add_2,std::placeholders::_1); for(int i = 0;i<10;++i) { call_when_even(i,fr); } std::cout<<std::endl; }
}
|
占位符
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| #include <iostream> #include <functional> void output(int x, int y) { std::cout << x << " " << y << std::endl; } int main(void) { std::bind(output, 1, 2)(); std::bind(output, std::placeholders::_1, 2)(1); std::bind(output, 2, std::placeholders::_1)(1); std::bind(output, 2, std::placeholders::_2)(1); std::bind(output, 2, std::placeholders::_2)(1, 2); std::bind(output, std::placeholders::_1,std::placeholders::_2)(1, 2); std::bind(output, std::placeholders::_2,std::placeholders::_1)(1, 2); return 0; }
|
bind简化和增强bind1st和bind2nd
其实bind简化和增强了之前标准库中bind1st和bind2nd,它完全可以替代bind1s和bind2st,并且能组合函数。我们知道,bind1st和bind2nd的作用是将一个二元算子转换成一个一元算子,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12
|
10的元素的个数
int count = std::count_if(coll.begin(), coll.end(), std::bind1st(less<int>(), 10));
10的元素
int count = std::count_if(coll.begin(), coll.end(), std::bind2nd(less<int>(), 10));
|
本质上是对一个二元函数less的调用,但是它却要分别用bind1st和bind2nd,并且还要想想到底是用bind1st还是bind2nd,用起来十分不便。
现在我们有了bind,就可以以统一的方式去实现了,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12
|
10的元素的个数
int count = std::count_if(coll.begin(), coll.end(), std::bind1st(less<int>(), 10));
10的元素
int count = std::count_if(coll.begin(), coll.end(), std::bind2nd(less<int>(), 10));
|
这样就不用关心到底是用bind1st还是bind2nd,只需要使用bind即可。
2.使用组合bind函数
bind还有一个强大之处就是可以组合多个函数。假设要找出集合中大于5小于10的元素个数应该怎么做呢?
首先,需要一个用来判断是否大于5的功能闭包,代码如下:
1
| std::bind(std::greater<int>(), std::placeholders::_1, 5);
|
这里std::bind返回的仿函数只有一个int参数。当输入了这个int参数后,输入的int值将直接和5进行大小比较,并在大于5时返回true。
然后,我们需要一个判断是否小于10的功能闭包:
1
| std::bind(std::greater<int>(), std::placeholders::_1, 5);
|
有了这两个闭包之后,只需要用逻辑与把它们连起来:
1 2 3 4
| using std::placeholders::_1; std::bind(std::logical_and<bool>(), std::bind(std::greater<int>(), _1, 5), std::bind(std::less_equal<int>(), _1, 10));
|
然后就可以复合多个函数(或者说闭包)的功能:
1 2 3 4 5 6 7 8 9 10 11
| using std::placeholders::_1;
5小于
10的元素个数
auto f = std::bind(std::logical_and<bool>(), std::bind(std::greater<int>(), _1, 5), std::bind(std::less_equal<int>(), _1, 10)); int count = std::count_if(coll.begin(), coll.end(), f);
|