C++11中的std::bind


C++11中的std::bind

最近在看看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

example:

#include <iostream>
#include <typeinfo>
#include <functional>
#include <string.h>
#include <iostream>
#include <typeinfo>
#include <functional>
#include <string.h>
using namespace std;

int add(int a, int b, int c)
{
        return a+b+c;
}

class Utils{
public:
        Utils(const char* name){
                strcpy(_name, name);
        }

        void SayHello(const char* name) const{
                std::cout<<_name<<" say : hello "<<name<<endl;
        }

        static int getId(){
                return 1001;
        }


private:
        char _name[32];
};

int main()
{
        auto add2 = std::bind(add, std::placeholders::_1, 1, 2);
        int i=add2(5);
        std::cout<<i<<std::endl;
        std::cout<<typeid(add2).name()<<endl;

        cout<<"------------------------------------"<<endl;

        Utils util("xiaoming");
        //綁定類成員
        auto sayHello = std::bind(&Utils::SayHello, util, std::placeholders::_1);
        sayHello("xiaodonmg");

        auto SayHelloKit = std::bind(&Utils::SayHello, util, "kit");
        SayHelloKit();


        //綁定靜態成員
        auto getId = std::bind(&Utils::getId);
        cout<<getId()<<endl;



        return 0;
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM