C++ function/bind
function/bind
1. std::function
i. 是一个函数的包装器
ii. std::function<R(T1, T2, ..., TN)>
iii. 这是一个模板实现的函数对象类,它可以包装其它任意的函数对象,而被包装的函数对象具有类型为T1,T2,…,TN的参数,其返回值为R类型
iv. function 对象的最大用处在于实现函数回调
2. bind
i. bind是这样一种机制,它可以预先把指定可调用实体的某些参数绑定到已有的变量,产生一个新的可调用实体(可用实体 就是 函数对象)
ii. 绑定的参数的个数不受限制
iii. 绑定的具体哪些参数也不受限制,由用户指定
iv. bind预先绑定的参数需要传具体的变量或值进去,是pass-by-value(值传递)的
v. 对于不事先绑定的参数,需要传std::placeholders进去,从_1开始,依次递增
vi. bind的返回值是可调用实体(也即 函数对象),可以直接赋给std::function对象.
1 function.cc 2 3 #include <functional> 4 #include <iostream> 5 6 struct Foo { 7 Foo(int num) : num_(num) {} 8 9 void print_add(int i) const 10 { 11 std::cout << num_+i << '\n'; 12 } 13 14 int num_; 15 }; 16 17 void print_num(int i) 18 { 19 std::cout << i << '\n'; 20 } 21 22 struct PrintNum { 23 void operator()(int i) const //重载() 符号运算符 24 { 25 std::cout << i << '\n'; 26 } 27 }; 28 29 int main() 30 { 31 // store a free function 32 std::function<void(int)> f_display = print_num; //function 包装一个参数为int,返回值为void 的函数,定义一个函数对象f_display,并将函数常量赋值给这个对象, 这是对常量函数进行包装。 33 f_display(-9); 34 35 // store a call to a member function 36 std::function<void(const Foo&, int)> f_add_display = &Foo::print_add; //把Foo的成员函数赋值给函数对象f_add_display,这是对成员函数进行包装。 37 const Foo foo(314159); 38 f_add_display(foo, 1); //foo传的是一个this 指针。 39 40 // store a call to a function object 41 std::function<void(int)> f_display_obj = PrintNum(); //对函数对象进行包装,后面的括号必须要加,表示一个函数。 42 f_display_obj(18); 43 44 //-------------------------------bind---------------------------------- 45 //bind函数 可以预先传入函数的参数,即预先绑定参数,后续要传的参数std::placeholder::_1代替。 46 47 // store the result of a call to std::bind 48 std::function<void()> f_display_31337 = std::bind(print_num, 31337); 49 f_display_31337(); 50 51 //以前没用function时,可以使用 auto 进行自动推断: 52 //auto f_display_31337 = std::bind(print_num, 31337); 53 //f_display_31337(); 54 55 // store a call to a member function and object 56 std::function<void(int)> f_add_display2= std::bind( &Foo::print_add, foo, std::placeholders::_1 ); 57 //这里使用了占位符; 当要用function包装一个成员函数时,要把this指针一同传进去,如第2个函数;但是当使用bind 之后,可以预先的将this指针绑定到函数中,就不能单独添加this指针,它直接将一个对象作为参数。 58 f_add_display2(2); 59 60 61 // store a call to a member function and object ptr 62 std::function<void(int)> f_add_display3= std::bind( &Foo::print_add, &foo, std::placeholders:: _1 ); 63 f_add_display3(3); 64 }
//之前(6/30)封装Thread的时候,是采用面向对象的方式。每一次当要执行一个线程的时候都要继承一个Thread类,然后再去把他的虚函数run实现,将他的具体任务留给派生类去实现,实现一个多态的形式。
当有了function 和bind之后,我们就可以用另外一种方式实现多态。
(这是基于对象的一种写法)
1 Thread.h 2 3 #include<pthread.h> 4 #include<functional> 5 6 #ifndef __BASED_THREAD_H 7 #define __BASED_THREAD_H 8 9 class Thread 10 { 11 public: 12 typedef std::function<void(void)> ThreadCallback; //这里定义的是一个function函数对象,只要满足模型void(void),都可以将函数对象赋给它。 13 14 public: 15 Thread(ThreadCallback callback); //自定义构造函数的声明,参数是一个函数对象 16 ~Thread(); 17 18 void start(); 19 void join(); 20 21 static void *runThread(void *); 22 bool isRunning() const; 23 24 private: 25 pthread_t pthId_; 26 bool isRunning_; 27 ThreadCallback callback_; //通过构造函数将外部具体的函数对象注册进来,赋值给callback_. 然后实际在runThread()函数里去调用callback_这个方法。 28 }; 29 #endif
1 Thread.cc 2 3 #include “Thread.h” 4 #include<iostream> 5 6 Thread::Thread(ThreadCallback callback) //自定义构造函数的定义 7 : pthId_(0), 8 isRunning_(false), 9 callback_(callback) 10 { 11 std::cout << “Thread::Thread() ” << std::endl; 12 } 13 14 Thread::~Thread() 15 { 16 pthread_detach(pthId_); 17 isRunning_ = false; 18 } 19 20 void Thread::start() 21 { 22 pthread_create(&pthId_, NULL, runInThread, this); //创建线程,调用启动函数runInThread(). 23 isRunning_ = true; 24 } 25 26 void Thread::join() 27 { 28 pthread_join(pthId_, NULL); 29 isRunning_ = false; 30 } 31 32 void * Thread::runInThread(void *arg) 33 { 34 Thread *pThread = static_cast<Thread *>(arg); //显示转换 35 pThread->callback_(); //callback_()函数是创建pThread对象的时候注册来的 36 //是通过构造函数将外部具体的函数对象注册进来,赋值给callback_. 然后实际在runThread()函数里去调用callback_这个方法。 37 } 38 39 bool Thread::isRunning() const 40 { 41 return isRunning_; 42 }
1 test_main.cc 2 3 #include “Thread.h” 4 #incldue<unistd.h> 5 #include<time.h> 6 #include<stdlib.h> 7 #include<iostream> 8 9 void print_num(void) //与Thread头文件中function绑定的函数类型是一样的。 10 { 11 ::srand(time(NULL)); 12 while(1) 13 { 14 int inum = ran() %100; 15 std::cout << “print a num: ” << inum << std::endl; 16 sleep(1); 17 } 18 } 19 20 struct Foo 21 { 22 Foo(int num) : num_(num){} 23 24 void print_num(int i) 25 { 26 std::cout << “print num_ + i = ” << num_ + I <<std::endl; 27 } 28 29 int num_; 30 }; 31 32 int main(void) 33 { 34 //情况一: 35 Thread thread(print_num); //创建Thread对象,调用自定义的构造函数; 注册回调函数print_num。 36 37 //情况二: 38 Foo foo(10); 39 Thread thread(std::bind(&Foo::print_num, foo, 20)); 40 //bind 函数返回一个绑定好参数的函数对象。 41 42 thread.start(); 43 thread.join(); 44 45 return 0; 46 }
综合步骤:
typedef std::function<void(void)> ThreadCallback;
//可将对应格式的函数赋值给ThreadCallback;
——————————————————————————————————
设置类的私有成员:
ThreadCallback callback_;
//通过该类构造函数或者用来赋值的成员函数将外部具体函数或者本类的成员函数注册进来,赋值给 callback_, 然后实际在其他函数中作为此类对象的成员函数来调用。