Chinaunix首页 | 论坛 | 博客
  • 博客访问: 7888879
  • 博文数量: 701
  • 博客积分: 2150
  • 博客等级: 上尉
  • 技术积分: 13233
  • 用 户 组: 普通用户
  • 注册时间: 2011-06-29 16:28
个人简介

天行健,君子以自强不息!

文章分类

全部博文(701)

文章存档

2019年(2)

2018年(12)

2017年(76)

2016年(120)

2015年(178)

2014年(129)

2013年(123)

2012年(61)

分类: C/C++

2015-12-22 17:18:09

最近在看看cocos2dx的源代码,发现了cocos2dx 3.0相对于2.0改动了很多,
最大的改变就是大量的使用了C++11的特性,比如auto等。
其中有一个关于回调函数绑定的宏定义就使用了std::bind特性


// new callbacks based on C++11
#define CC_CALLBACK_0(__selector__,__target__, ...) std::bind(&__selector__,__target__, ##__VA_ARGS__)
#define CC_CALLBACK_1(__selector__,__target__, ...) std::bind(&__selector__,__target__, std::placeholders::_1, ##__VA_ARGS__)
#define CC_CALLBACK_2(__selector__,__target__, ...) std::bind(&__selector__,__target__, std::placeholders::_1, std::placeholders::_2, ##__VA_ARGS__)
#define CC_CALLBACK_3(__selector__,__target__, ...) std::bind(&__selector__,__target__, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3,
##__VA_ARGS__)


非常简练的宏定义,对于没有接触过C++11的朋友来说,真的是一头雾水,这货是什么,真的是C++吗?
所以笔者就写了这篇文章来讲解。


一、C++发展的历史
C++经过多年发展,真正正式公布出的标准只有三个C++98,C++03,C++11。
其中C++03只是C++98的小幅度修订,在笔者看来,C++发展的历史,就是一个不断吸收新特性的历史。
从最早的面向过程,面向对象,模板编程,到现在的函数式编程,C++一直都是在吸收新特性。
lambda就是函数式编程闭包的特性。


二、何为bind
bind是这样一种机制,它可以预先把指定可调用实体的某些参数绑定到已有的变量,
产生一个新的可调用实体,这种机制在回调函数的使用过程中也颇为有用。

其实最早在C++98的时候,就已经有了std::bind1st和std::bind2nd分别用来绑定functor的两个参数,
具体代码就不演示了,查查资料就知道了。这个特性在当时并没有引起太多的重视,可以说是食之无味。

C++11中提供了std::bind,可以说是一种飞跃的提升,bind本身是一种延迟计算的思想,
它本身可以绑定普通函数、全局函数、静态函数、类静态函数甚至是类成员函数。

  1. #include <iostream>
  2. #include <functional>
  3. using namespace std;


  4. int TestFunc(int a, char c, float f)
  5. {
  6.     cout << a << endl;
  7.     cout << c << endl;
  8.     cout << f << endl;


  9.     return a;
  10. }


  11. int main()
  12. {
  13.     auto bindFunc1 = bind(TestFunc, std::placeholders::_1, 'A', 100.1);
  14.     bindFunc1(10);


  15.     cout << "=================================\n";


  16.     auto bindFunc2 = bind(TestFunc, std::placeholders::_2, std::placeholders::_1, 100.1);
  17.     bindFunc2('B', 10);


  18.     cout << "=================================\n";


  19.     auto bindFunc3 = bind(TestFunc, std::placeholders::_2, std::placeholders::_3, std::placeholders::_1);
  20.     bindFunc3(100.1, 30, 'C');


  21.     return 0;
  22. }



从上面的代码可以看到,bind能够在绑定时候就同时绑定一部分参数,
未提供的参数则使用占位符表示,然后在运行时传入实际的参数值。

PS:绑定的参数将会以值传递的方式传递给具体函数,占位符将会以引用传递。


众所周知,静态成员函数其实可以看做是全局函数,而非静态成员函数则需要传递this指针作为第一个参数,
所以std::bind能很容易地绑定成员函数。


cocos2dx中的CC_CALLBACK系列的宏其实就是一种封装好的std::bind,
它默认认为绑定的就是成员函数,帮助开发者简化了代码。


三、总结
bind最终将会生成一个可调用对象,这个对象可以直接赋值给std::function对象,
而std::bind绑定的可调用对象可以是Lambda表达式或者类成员函数等可调用对象,
这个是cocos2dx中的一般用法。它能随意绑定任何函数,将所有的函数都能统一到std::function
阅读(1786) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~