C++11 中的std::function和std::bind

1. 可調(diào)用對(duì)象

可調(diào)用對(duì)象有一下幾種定義:

  • 是一個(gè)函數(shù)指針盐须,參考 C++ 函數(shù)指針和函數(shù)類型彤蔽;
  • 是一個(gè)具有operator()成員函數(shù)的類的對(duì)象偿渡;
  • 可被轉(zhuǎn)換成函數(shù)指針的類對(duì)象颠放;
  • 一個(gè)類成員函數(shù)指針饼酿;

C++中可調(diào)用對(duì)象的雖然都有一個(gè)比較統(tǒng)一的操作形式棉圈,但是定義方法五花八門涩堤,這樣就導(dǎo)致使用統(tǒng)一的方式保存可調(diào)用對(duì)象或者傳遞可調(diào)用對(duì)象時(shí),會(huì)十分繁瑣分瘾。C++11中提供了std::function和std::bind統(tǒng)一了可調(diào)用對(duì)象的各種操作胎围。

不同類型可能具有相同的調(diào)用形式,如:

// 普通函數(shù)
int add(int a, int b){return a+b;} 

// lambda表達(dá)式
auto mod = [](int a, int b){ return a % b;}

// 函數(shù)對(duì)象類
struct divide{
    int operator()(int denominator, int divisor){
        return denominator/divisor;
    }
};

上述三種可調(diào)用對(duì)象雖然類型不同德召,但是共享了一種調(diào)用形式:

int(int ,int)

std::function就可以將上述類型保存起來(lái)白魂,如下:

std::function<int(int ,int)>  a = add; 
std::function<int(int ,int)>  b = mod ; 
std::function<int(int ,int)>  c = divide(); 

2. std::function

  • std::function 是一個(gè)可調(diào)用對(duì)象包裝器,是一個(gè)類模板上岗,可以容納除了類成員函數(shù)指針之外的所有可調(diào)用對(duì)象福荸,它可以用統(tǒng)一的方式處理函數(shù)、函數(shù)對(duì)象肴掷、函數(shù)指針敬锐,并允許保存和延遲它們的執(zhí)行。
  • 定義格式:std::function<函數(shù)類型>呆瞻。
  • std::function可以取代函數(shù)指針的作用台夺,因?yàn)樗梢匝舆t函數(shù)的執(zhí)行,特別適合作為回調(diào)函數(shù)使用痴脾。它比普通函數(shù)指針更加的靈活和便利颤介。

3. std::bind

可將std::bind函數(shù)看作一個(gè)通用的函數(shù)適配器,它接受一個(gè)可調(diào)用對(duì)象,生成一個(gè)新的可調(diào)用對(duì)象來(lái)“適應(yīng)”原對(duì)象的參數(shù)列表买窟。

std::bind將可調(diào)用對(duì)象與其參數(shù)一起進(jìn)行綁定丰泊,綁定后的結(jié)果可以使用std::function保存薯定。std::bind主要有以下兩個(gè)作用:

  • 將可調(diào)用對(duì)象和其參數(shù)綁定成一個(gè)防函數(shù)始绍;
  • 只綁定部分參數(shù),減少可調(diào)用對(duì)象傳入的參數(shù)话侄。

3.1 std::bind綁定普通函數(shù)

double my_divide (double x, double y) {return x/y;}
auto fn_half = std::bind (my_divide,_1,2);  
std::cout << fn_half(10) << '\n';                        // 5
  • bind的第一個(gè)參數(shù)是函數(shù)名亏推,普通函數(shù)做實(shí)參時(shí),會(huì)隱式轉(zhuǎn)換成函數(shù)指針年堆。因此std::bind (my_divide,_1,2)等價(jià)于std::bind (&my_divide,_1,2)吞杭;
  • _1表示占位符,位于<functional>中变丧,std::placeholders::_1芽狗;

3.2 std::bind綁定一個(gè)成員函數(shù)

struct Foo {
    void print_sum(int n1, int n2)
    {
        std::cout << n1+n2 << '\n';
    }
    int data = 10;
};
int main() 
{
    Foo foo;
    auto f = std::bind(&Foo::print_sum, &foo, 95, std::placeholders::_1);
    f(5); // 100
}
  • bind綁定類成員函數(shù)時(shí),第一個(gè)參數(shù)表示對(duì)象的成員函數(shù)的指針痒蓬,第二個(gè)參數(shù)表示對(duì)象的地址童擎。
  • 必須顯示的指定&Foo::print_sum,因?yàn)榫幾g器不會(huì)將對(duì)象的成員函數(shù)隱式轉(zhuǎn)換成函數(shù)指針攻晒,所以必須在Foo::print_sum前添加&顾复;
  • 使用對(duì)象成員函數(shù)的指針時(shí),必須要知道該指針屬于哪個(gè)對(duì)象鲁捏,因此第二個(gè)參數(shù)為對(duì)象的地址 &foo芯砸;

3.3 綁定一個(gè)引用參數(shù)

默認(rèn)情況下,bind的那些不是占位符的參數(shù)被拷貝到bind返回的可調(diào)用對(duì)象中给梅。但是假丧,與lambda類似,有時(shí)對(duì)有些綁定的參數(shù)希望以引用的方式傳遞动羽,或是要綁定參數(shù)的類型無(wú)法拷貝包帚。

#include <iostream>
#include <functional>
#include <vector>
#include <algorithm>
#include <sstream>
using namespace std::placeholders;
using namespace std;

ostream & print(ostream &os, const string& s, char c)
{
    os << s << c;
    return os;
}

int main()
{
    vector<string> words{"helo", "world", "this", "is", "C++11"};
    ostringstream os;
    char c = ' ';
    for_each(words.begin(), words.end(), 
                   [&os, c](const string & s){os << s << c;} );
    cout << os.str() << endl;

    ostringstream os1;
    // ostream不能拷貝,若希望傳遞給bind一個(gè)對(duì)象曹质,
    // 而不拷貝它婴噩,就必須使用標(biāo)準(zhǔn)庫(kù)提供的ref函數(shù)
    for_each(words.begin(), words.end(),
                   bind(print, ref(os1), _1, c));
    cout << os1.str() << endl;
}

4. 指向成員函數(shù)的指針

通過(guò)下面的例子,熟悉一下指向成員函數(shù)的指針的定義方法羽德。

#include <iostream>
struct Foo {
    int value;
    void f() { std::cout << "f(" << this->value << ")\n"; }
    void g() { std::cout << "g(" << this->value << ")\n"; }
};
void apply(Foo* foo1, Foo* foo2, void (Foo::*fun)()) {
    (foo1->*fun)();  // call fun on the object foo1
    (foo2->*fun)();  // call fun on the object foo2
}
int main() {
    Foo foo1{1};
    Foo foo2{2};
    apply(&foo1, &foo2, &Foo::f);
    apply(&foo1, &foo2, &Foo::g);
}
  • 成員函數(shù)指針的定義:void (Foo::*fun)()几莽,調(diào)用是傳遞的實(shí)參: &Foo::f;
  • fun為類成員函數(shù)指針宅静,所以調(diào)用是要通過(guò)解引用的方式獲取成員函數(shù)*fun,即(foo1->*fun)();

參考

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末章蚣,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌纤垂,老刑警劉巖矾策,帶你破解...
    沈念sama閱讀 206,602評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異峭沦,居然都是意外死亡贾虽,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,442評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門吼鱼,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)蓬豁,“玉大人,你說(shuō)我怎么就攤上這事菇肃〉胤啵” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,878評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵琐谤,是天一觀的道長(zhǎng)蟆技。 經(jīng)常有香客問(wèn)我,道長(zhǎng)斗忌,這世上最難降的妖魔是什么质礼? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,306評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮飞蹂,結(jié)果婚禮上几苍,老公的妹妹穿的比我還像新娘。我一直安慰自己陈哑,他們只是感情好妻坝,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,330評(píng)論 5 373
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著惊窖,像睡著了一般刽宪。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上界酒,一...
    開(kāi)封第一講書(shū)人閱讀 49,071評(píng)論 1 285
  • 那天圣拄,我揣著相機(jī)與錄音,去河邊找鬼毁欣。 笑死庇谆,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的凭疮。 我是一名探鬼主播饭耳,決...
    沈念sama閱讀 38,382評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼执解!你這毒婦竟也來(lái)了寞肖?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,006評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎新蟆,沒(méi)想到半個(gè)月后觅赊,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,512評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡琼稻,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,965評(píng)論 2 325
  • 正文 我和宋清朗相戀三年吮螺,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片欣簇。...
    茶點(diǎn)故事閱讀 38,094評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡规脸,死狀恐怖坯约,靈堂內(nèi)的尸體忽然破棺而出熊咽,到底是詐尸還是另有隱情,我是刑警寧澤闹丐,帶...
    沈念sama閱讀 33,732評(píng)論 4 323
  • 正文 年R本政府宣布横殴,位于F島的核電站,受9級(jí)特大地震影響卿拴,放射性物質(zhì)發(fā)生泄漏衫仑。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,283評(píng)論 3 307
  • 文/蒙蒙 一堕花、第九天 我趴在偏房一處隱蔽的房頂上張望文狱。 院中可真熱鬧,春花似錦缘挽、人聲如沸瞄崇。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,286評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)苏研。三九已至,卻和暖如春腮郊,著一層夾襖步出監(jiān)牢的瞬間摹蘑,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,512評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工轧飞, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留衅鹿,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,536評(píng)論 2 354
  • 正文 我出身青樓过咬,卻偏偏與公主長(zhǎng)得像大渤,于是被迫代替她去往敵國(guó)和親援奢。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,828評(píng)論 2 345

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

  • 接著上節(jié) condition_varible 纬霞,本節(jié)主要介紹future的內(nèi)容,練習(xí)代碼地址瞳抓。本文參考http:/...
    jorion閱讀 14,761評(píng)論 1 5
  • 前言 把《C++ Primer》[https://book.douban.com/subject/25708312...
    尤汐Yogy閱讀 9,506評(píng)論 1 51
  • 函數(shù)和對(duì)象 1翠桦、函數(shù) 1.1 函數(shù)概述 函數(shù)對(duì)于任何一門語(yǔ)言來(lái)說(shuō)都是核心的概念销凑。通過(guò)函數(shù)可以封裝任意多條語(yǔ)句,而且...
    道無(wú)虛閱讀 4,525評(píng)論 0 5
  • 文/西西 你睡去的那片山崗 年年青蔥翠綠 只是你再也不與我們 笑談塵世 幾回回夢(mèng)見(jiàn) 你只是微笑 再無(wú)任何的話語(yǔ) 恍...
    花語(yǔ)清溪閱讀 383評(píng)論 5 11
  • 電話是琳達(dá)打來(lái)的蜕窿。 我問(wèn)琳達(dá)有什么吩咐渠羞,她在電話里咯咯咯笑得像個(gè)小母雞一樣。 我一聽(tīng)她這笑聲荧恍,就覺(jué)得不妙送巡。 果然盒卸,...
    黃咚咚閱讀 1,901評(píng)論 17 27