c++ Boost库之boost::bind学习
刚开始学c++,就看boost库其实有点小小的不情愿。
团队要求必掌握的Boost库:
boost::bind
boost::function
boost::Signals2
学习前奏:在写关于cocos2d-x的helloworld例子时,一直搞不明白这句代码的意思(以前搞java的)
1 void UpdateGame(cocos2d::ccTime time);
2 void CollideDetect(cocos2d::ccTime time);
3
4 this->schedule( schedule_selector(HelloWorld::UpdateGame), 0.05f );
5 this->schedule( schedule_selector(HelloWorld::CollideDetect) );
最近知道原来方法也是可以做为一种类型传其它函数。把参数定义为类型
1 typedef void (*FUN_TYPE) (int);
2
3 #define schedule_selector FUN_TYPE
4
5 void schedule( FUN_TYPE f, int i) {
6 f(i);
7 }
8
9
10 void UpdateGame(int i) {
11 printf("hello %d", i);
12 }
13
14
15 int _tmain(int argc, _TCHAR* argv[])
16 {
17 schedule( schedule_selector(UpdateGame), 1);
18 return 0;
19 }
绕了半天做了个行似的。为什么在cocos2d-x要这样做呢?抽象时,引擎制作者并不知道每一帧动画,或没隔x时间,执行一下你的UpdateGame()方法,由于你起名字不一定起UpdateGame()而且不一定有几个那样的方法(可以重写一下UpdateGame()使他执行你想关联的方法,但是执行的时间也不一定相同所以操作复杂度大大增加),所以直接定义成方法类型。
从boost::bind开始学习Boost库:boost::bind is a generalization of the standard functions std::bind1st and std::bind2nd. It supports arbitrary function objects, functions, function pointers, and member function pointers, and is able to bind any argument to a specific value or route input arguments into arbitrary positions.译:boost::bind是标准方法std::bind1st&std::bind2nd的一般化。它支持任意的方法对象s,方法s,方法s的指针,和成员方法指针s,它可以给任何参数绑定一个指定的值,或者发送参数放到任何位置。比较痛苦的事,现在我还没看过,std::bind1st&std::bind2nd。我感觉自己有点误入歧途了,虽然刚刚掌握函数类型,但这肯定不是问题的关键。
1 class funtest {
2 public:
3 string str;
4 public:
5 void doSth(char c) {
6 cout << "char: " << c << endl;
7 }
8
9 void test() {
10 for_each(str.begin(), str.end(), bind1st(mem_fun(&funtest::doSth),this));
11 }
12 };
13
14 int main(int argc, char* argv[])
15 {
16 funtest test;
17 test.str = "ABCDEFG";
18 test.test();
19 return 0;
20 }
void doSth(char c) {
cout << "char: " << c << endl;
}
int main(int argc, char* argv[])
{
string str = "abc";
for_each(str.begin(), str.end(), doSth);
return 0;
}
一个用bind1st一个不用,都能得到相同的结果,难道是第一个在类体中的原因?先看一下bind1st和bind2nd的概念:它们是类库模版,他们有个有趣的特征,能将某个值绑定到一个二元函数对象的一个参数之上,例如:
有函数T f(x, y);bind1st(f, x1)将生成一个与f(x, y) 类型一致的函数对象F;这里x1是一个给定值,绑定到函数f的x上。
有函数T f(x, y);bind2nd(f, y1)将生成一个与f(x, y) 类型一致的函数对象F;同理。
stl的for_each还不太会弄,先屏蔽掉,专心弄清楚bind1st&bind2st上面的bind1st看起来有点复杂,绑定的是成员函数了,还是看一下msdn文档吧
1 template<class Operation, class Type>
2 binder1st <Operation> bind1st(
3 const Operation& _Func,
4 const Type& _Left
5 );
Function binders are a kind of function adaptor and,because they return function objects,can be used in cetain types of function composition to construct more complicated and powerful expressions.if _Func is an object of type Operation and c is a constant,then bind1st(_Func, c )is equivalent to the binder1st constructor binder1st<Operation>(_Func, c )and is more convenient.
先不仔细研究bind1st&bind2nd等了,大概就是把二元函数改变成一元函数符合自己编程的需求。返回值是一个 function object,到bind中的function object再追究以前了解的function object的一些问题;最后再把总体知识总结起来,现在很多认识都是错的。
boost::bind开始,先下载boost库,下载的时间来了解一下什么是function obejct:Function object 是一个对象,不过它的行为表现的像函数。一般而言,它是由一个重载了operator()的类所实例化得来的对象。Function object的涵义比通常意义上的函数更广泛,以为它可以在多次调用之间保持某种“状态”——这和静态局部变量有异曲同工之妙;不过这种“状态”还可以被初始化,还可以从外面来检测,这可要比静态局部变量强了。
bind with functions and function pointers
bing with function objects:In the gneral case, the return type of the generated function object's operator()has to be specified explicitly (without a typeof operator the return type cannot be inferred) 一般情况下,产生的方法对象的operator()的类型必须特别的指明。
1 struct F
2 {
3 int operator()(int a, int b) { return a - b; }
4 bool operator()(long a, long b) { return a == b; }
5 };
6
7 F f;
8
9 int x = 104;
10
11 bind<int>(f, _1, _1)(x); // f(x, x), i.e. zero
Using bind with pointers to members
pointers to member functions and pointers to data members are not function objects, because they do not support operator().for convenience, bind accepts member pointers as its first argument, and the behavior is as if boost::mem_fn has been used to convert the member pointer into a function object. In other words, the expression
bind(&X::f, args) is equivalent to bind<R>(men_fn(&X::f), args)
where R is the return type of X::f(for member functions) or the type of the member(for data members). [Note:mem_fn creates function objects that are able to accept a pointer,a reference, or a smart pointer to an object as its first argument]
Using nested binds for function compostion // 这个暂时不仔细研究
Some of the arguments passed to bind may be nested bind expression themselves:
bind(f, bind(g,_1))(x);
the inner bind expressions are evaluated, in unspecified order, before the outer bind when the function object is called;the results of the evaluation are then substitued in their place when the outer bind is evaluated.In the exaple above, when the function object is called with the argument list(x),bind(g, _1)(x) is evaluated first, yielding g(x), and then bind(f, g(x))(x) is evaluated,yielding the final result f(g(x)).
安装Boost本以为很麻烦,结果在boost压缩包中index.html中介绍说“most boost libraries are header_only:they consist entirely of header files containing templates and inline functions,and require no separately-compiled library binaries or special treatment when linking” 好了,把源码都在头文件中,只需把头文件目录包含到项目中就可以了。
笔记完成,看书我比较喜欢抄书,这样印象深刻,当时考会计时,几乎把会计基础、财会和审计整本书抄了一遍,比单纯的看效果好多了。
回过头来看,我已经不知道我都看了哪些东西,哪些东西当时思考的有问题,但是自己对几个概念的了解加深了:
1.函数类型——typedef 定义作用,说白了传函数就是传指针,不过对于c++这中强制类型检查的语言不得不给编译器一个模版来识别这种类型(这句话有没有问题?以后再想想),这是以前java中所没有的;
2.object functions 对象函数,就是一种特殊的class(stuct)重载操作符operator(),bind的时候通过返回值类型参数个数和类型来确定是哪个operator()。这样用起来和用bind方法看起来十分相似。
3.绑定成员函数,成员函数函数名不是它的指针,(&X::f)这样写才行,引出bind(&X::f, args) == bind<R>(men_fn(&X::f),args)。这样第三处代码funtest中bind1st(mem_fun(&funtest::doSth),this)也就可以猜出什么意思了,把this绑定到doSth的最左的变量上(成员变量this原本是默认绑定上的)。
最后stl中的for_each也明白了for_each(str.begin(), str.end(), bind1st(mem_fun(&funtest::doSth),this));把str中的每个元素作为参数送到第三个参数(是个函数的指针)所指向的函数。
boost::function
先把看bind文档时最后一个关于Function的例子贴上:
1 class button
2 {
3 public:
4
5 boost::function<void()> onClick;
6 };
7
8 class player
9 {
10 public:
11
12 void play();
13 void stop();
14 };
15
16 button playButton, stopButton;
17 player thePlayer;
18
19 void connect()
20 {
21 playButton.onClick = boost::bind(&player::play, &thePlayer);
22 stopButton.onClick = boost::bind(&player::stop, &thePlayer);
23 }
我现在可以通过boost::bind()的返回值,做一个猜想,boost::function<void()> onClick;是一个函数类型的指针,指向play()和stop(),this指针取thePlayer的地址。
摘抄一下Introduction:The Boost.Function library contains a family of of class templates that are function object wrappers.The notion is similar to a generalized callback. It shares features with function pointers in that both define a call interface through which some implementation can be called, and the implementation that is invoked may change throughout the course of the program.
Generally, any place in which a function pointer would be used to defer a call or make a callback,Boost.Function can be used instead to allow the user greater flexibility in the implementation of the target. Targets can be any 'compatible' function object (or function pointer), meaning that the arguments to the interface designated by Boost.Function can be converted to the arguments of the target function object.//译:boost.function库包含一系列是包裹函数对象类的模版。这个概念很像通用的一个回调。它与函数指针(都定义了一个调用接口通过实现就可以被调用)来共用表现(features 啥东西呢 应该指函数吧),通过这个程序实现就可以被变化的调用。一般来说,在函数指针被调用或回调,Boost.Function会被替代来允许用户更加灵活在目标的实现上。目标可以是任何兼容的对象函数(或函数指针),意味着用Boost.Function类型接口参数可以被转换为目标对象函数的参数。——翻译的太差 理解了后再改下
大胆猜测一下,boost::function绑定类似多态机制(virtual函数的动态绑定)。