最近在看看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本身是一种延迟计算的思想,
它本身可以绑定普通函数、全局函数、静态函数、类静态函数甚至是类成员函数。
-
#include <iostream>
-
#include <functional>
-
using namespace std;
-
-
-
int TestFunc(int a, char c, float f)
-
{
-
cout << a << endl;
-
cout << c << endl;
-
cout << f << endl;
-
-
-
return a;
-
}
-
-
-
int main()
-
{
-
auto bindFunc1 = bind(TestFunc, std::placeholders::_1, 'A', 100.1);
-
bindFunc1(10);
-
-
-
cout << "=================================\n";
-
-
-
auto bindFunc2 = bind(TestFunc, std::placeholders::_2, std::placeholders::_1, 100.1);
-
bindFunc2('B', 10);
-
-
-
cout << "=================================\n";
-
-
-
auto bindFunc3 = bind(TestFunc, std::placeholders::_2, std::placeholders::_3, std::placeholders::_1);
-
bindFunc3(100.1, 30, 'C');
-
-
-
return 0;
-
}
从上面的代码可以看到,bind能够在绑定时候就同时绑定一部分参数,
未提供的参数则使用占位符表示,然后在运行时传入实际的参数值。
PS:绑定的参数将会以值传递的方式传递给具体函数,占位符将会以引用传递。
众所周知,静态成员函数其实可以看做是全局函数,而非静态成员函数则需要传递this指针作为第一个参数,
所以std::bind能很容易地绑定成员函数。
cocos2dx中的CC_CALLBACK系列的宏其实就是一种封装好的std::bind,
它默认认为绑定的就是成员函数,帮助开发者简化了代码。
三、总结
bind最终将会生成一个可调用对象,这个对象可以直接赋值给std::function对象,
而std::bind绑定的可调用对象可以是Lambda表达式或者类成员函数等可调用对象,
这个是cocos2dx中的一般用法。它能随意绑定任何函数,将所有的函数都能统一到std::function
阅读(1791) | 评论(0) | 转发(0) |