C11新特性之std::function與std::bind

1. 什么是std::function

std::function其實就是一個類模板,含有c的函數(shù)指針概念其障。

類模版std::function是一種通用、多態(tài)的函數(shù)封裝。std::function的實例可以對任何可以調(diào)用的目標實體進行存儲、復制抵窒、和調(diào)用操作,這些目標實體包括普通函數(shù)叠骑、Lambda表達式李皇、函數(shù)指針、以及其它函數(shù)對象等宙枷。

簡要來說:std::function是將所有可調(diào)用的實體封裝起來掉房,形成了一個新的std::function對象茧跋,用戶在使用的時候不需要再去一一調(diào)用實體,只需要使用新的std::function來調(diào)用各實體

如下卓囚,std::function作為回調(diào)函數(shù)使用瘾杭,它可以調(diào)用任何有兩個int形參的返回值為int的對象

#include <iostream>
#include <functional>
#include <list>
using namespace std;

// 傳統(tǒng)C函數(shù)
int c_function(int a, int b)
{
    return a + b;
}

// 函數(shù)對象
class Functor
{
public:
    int operator()(int a, int b)
    {
        return a + b;
    }
};

int main(int argc, char** argv)
{
    Functor functor;
    std::list<std::function<int(int, int)>> callables;

    callables.push_back(c_function);
    callables.push_back(functor);
    callables.push_back([](int x, int y)->int{
        return x + y;
    });

    for (const auto& e : callables)
    {
        cout << e(3, 4) << endl;
    }
}

2.std::function作為形參

又因為std::function兼容c的函數(shù)指針,所以它還包含函數(shù)指針應有的特性捍岳。但是它又和函數(shù)指針不同富寿,函數(shù)指針只能指向一個函數(shù),而std::function可以指向任何可以被當做函數(shù)調(diào)用的對象
以下內(nèi)容來自

2.1 基于傳值的方式傳入?yún)?shù)

void registerCallBack(std::function<void()>);

2.2 基于引用的方式傳入?yún)?shù)

因為調(diào)用initWithFunction會產(chǎn)生臨時的std::function對象锣夹,屬于右值页徐,必須使用const,不然會報錯

bool CallFunc::initWithFunction(const std::function<void()> &func)
{
    _function = func;
    return true;
}

2.3 std::function的保存

轉移操作std::move效率更高

class CallBackHolder 
{
public:
  void registerCallBack(std::function<void()> func)
  {
    callback = std::move(func);
  } 
private:
  std::function<void()> callback; 
}

3. 類的成員函數(shù)作為函數(shù)入?yún)?/h2>

3.1 使用std::bind()和std::function來實現(xiàn)

std::bind完成了實體和函數(shù)地址的綁定,因為它的參數(shù)里面既有對象指針,又有函數(shù)指針,從而制造了一個std::function,然后std::function只要能正確處理那個this指針,那就能完成正確地調(diào)用了

class RTree

{
public:
         void searchOverlap(std::function<void(int)>f)
         {
                   f(2);
         }
};

class CallRtree
{
public:
         virtual void searchRes(int a)
         {
                   this->a = a;
         }
         void search()
         {
                   RTree rtree;
                   std::function<void(int)>functional = std::bind(&CallRtree::searchRes, this, std::placeholders::_1);
                  //通常直接寫成 auto a =std::bind(....);
                   rtree.searchOverlap(functional);
                   int v = this->a;
         }

private:
         int a;
}
int _tmain(intargc, _TCHAR* argv[])

{
         CallRtree caller;
         caller.search();
}

3.2 使用lambda表達式實現(xiàn)(先不說了银萍,以后復習了lamdba再來講)


2. 什么是std::bind

  • 將函數(shù)变勇、成員函數(shù)和閉包轉成function函數(shù)對象
  • 將多元(n>1)函數(shù)轉成一元函數(shù)或者(n-1)元函數(shù)。

bind是一種機制贴唇,可以預先把指定的可調(diào)用的實體的某些參數(shù)綁定到已有的變量搀绣,產(chǎn)生一個新的可調(diào)用實體。
它作為一個通用函數(shù)適配器戳气,接收一個可調(diào)用對象链患,生成一個新的可調(diào)用對象來適應原對象的參數(shù)列表

2.1 bind的使用方法

比如瓶您,存在一個這樣的函數(shù)check_size麻捻,因為這是一個二元函數(shù),當我們要將它作為find_if的參數(shù)呀袱,會出錯贸毕。因為find_if只接受一元函數(shù),那么如何解決呢夜赵?
一個方法是Lambda表達式明棍,還有一個方法就是使用std::bind

bool check_size(const string &s,string::size_type sz)
{
      return s.size()>=sz;
}

下面這個bind的函數(shù)只有一個占位符,即只需要傳入一個參數(shù)寇僧。它將check_size的第二個參數(shù)綁定在sz上摊腋,sz的值就是check_size的第二個參數(shù)的值,而check_size第一個參數(shù)需要傳入

auto wc = find_if(words.begin(),words.end(),bind(check_size,_1,sz));

2.2 bind的參數(shù)問題

auto g = bind(f,a,b,_2,c,_1);

如果現(xiàn)在我們調(diào)用g(3,5)嘁傀,那么就相當于bind(f,a,b,5,c,3);
所以_1相當于傳遞的第一個參數(shù)歌豺,_2相當于傳遞的第二個參數(shù)...以此類推。

需要注意:bind對于直接綁定的值心包,是以值傳遞的方式类咧,對于用_1這類,是使用引用傳遞。bind的返回值是可以調(diào)用的實體痕惋,所以通常我們都會將它和function聯(lián)合在一起使用区宇。

2.3 bind引用參數(shù)

有時候對于有些綁定的參數(shù)我們希望以引用方式傳遞,或者說要綁定的參數(shù)無法拷貝值戳。
比如ostream 流對象是無法拷貝的议谷,那么我們希望將它傳遞給bind而不拷貝它,就需要使用ref堕虹。
ref返回一個對象卧晓,包含給定的引用,是可以拷貝的赴捞。

for_each(words.begin(),words.end,bind(print,ref(os),_1,' '));

2.4 std::bind綁定成員函數(shù)和靜態(tài)成員函數(shù)

對于成員函數(shù)的綁定逼裆,我們一定需要一個調(diào)用者,也就是類的實例赦政!
需要注意的是胜宇,bind無法綁定重載函數(shù),因為當重載函數(shù)的參數(shù)個數(shù)不相同時恢着,bind也失去了它的意義桐愉。

class Utils {  
public:  
    Utils(const char* name) {  
        strcpy(_name, name);  
    }        
    void sayHello(const char* name) const {  
        std::cout << _name << " say: hello " << name << std::endl;  
    }        
    static int getId() {  
        return 10001;  
    }         
    int operator()(int i, int j, int k) const {  
        return i + j + k;  
    }       
private:  
    char _name[32];  
};  

int main(void) {  

    // 綁定成員函數(shù)  
    Utils utils("Vicky");  
    auto sayHello = std::bind(&Utils::sayHello, utils/*調(diào)用者*/, std::placeholders::_1);  
    sayHello("Jack");  

    // 綁定靜態(tài)成員函數(shù)  
    auto getId = std::bind(&Utils::getId);  
    std::cout << getId() << std::endl; 
}

2.5 bind與function搭配

在cocos2dx的源碼中,我們經(jīng)酬桑可以看到function作為函數(shù)形參从诲,而bind作為實參傳入

bool Label::multilineTextWrap(std::function<int(const std::u16string&, int, int)> nextTokenLen)
{}

bool Label::multilineTextWrapByChar()
{
      return multilineTextWrap(std::bind(getFirstCharLen, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
}
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市靡羡,隨后出現(xiàn)的幾起案子盏求,更是在濱河造成了極大的恐慌,老刑警劉巖亿眠,帶你破解...
    沈念sama閱讀 221,198評論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異磅废,居然都是意外死亡纳像,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評論 3 398
  • 文/潘曉璐 我一進店門拯勉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來竟趾,“玉大人,你說我怎么就攤上這事宫峦〔砻保” “怎么了?”我有些...
    開封第一講書人閱讀 167,643評論 0 360
  • 文/不壞的土叔 我叫張陵导绷,是天一觀的道長犀勒。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么贾费? 我笑而不...
    開封第一講書人閱讀 59,495評論 1 296
  • 正文 為了忘掉前任钦购,我火速辦了婚禮,結果婚禮上褂萧,老公的妹妹穿的比我還像新娘押桃。我一直安慰自己,他們只是感情好导犹,可當我...
    茶點故事閱讀 68,502評論 6 397
  • 文/花漫 我一把揭開白布唱凯。 她就那樣靜靜地躺著,像睡著了一般谎痢。 火紅的嫁衣襯著肌膚如雪磕昼。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,156評論 1 308
  • 那天舶得,我揣著相機與錄音掰烟,去河邊找鬼。 笑死沐批,一個胖子當著我的面吹牛纫骑,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播九孩,決...
    沈念sama閱讀 40,743評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼先馆,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了躺彬?” 一聲冷哼從身側響起煤墙,我...
    開封第一講書人閱讀 39,659評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎宪拥,沒想到半個月后仿野,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,200評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡她君,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,282評論 3 340
  • 正文 我和宋清朗相戀三年脚作,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片缔刹。...
    茶點故事閱讀 40,424評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡球涛,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出校镐,到底是詐尸還是另有隱情亿扁,我是刑警寧澤,帶...
    沈念sama閱讀 36,107評論 5 349
  • 正文 年R本政府宣布鸟廓,位于F島的核電站从祝,受9級特大地震影響襟己,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜哄褒,卻給世界環(huán)境...
    茶點故事閱讀 41,789評論 3 333
  • 文/蒙蒙 一稀蟋、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧呐赡,春花似錦退客、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,264評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至怀泊,卻和暖如春茫藏,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背霹琼。 一陣腳步聲響...
    開封第一講書人閱讀 33,390評論 1 271
  • 我被黑心中介騙來泰國打工务傲, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人枣申。 一個月前我還...
    沈念sama閱讀 48,798評論 3 376
  • 正文 我出身青樓售葡,卻偏偏與公主長得像,于是被迫代替她去往敵國和親忠藤。 傳聞我的和親對象是個殘疾皇子挟伙,可洞房花燭夜當晚...
    茶點故事閱讀 45,435評論 2 359

推薦閱讀更多精彩內(nèi)容