Boost源碼剖析:C++泛型函數(shù)指針類

字號(hào):

前奏
    如你所知,Boost庫(kù)是個(gè)特性完備,且具備工業(yè)強(qiáng)度的庫(kù),眾多C++權(quán)威的參與使其達(dá)到了登峰造極的程度。尤其泛型的強(qiáng)大威力在其中被發(fā)揮得淋漓盡致,令人瞠目結(jié)舌。
    然而弱水三千,我們只取一瓢飲。下面,我試圖從最單純的世界開(kāi)始,一步一步帶領(lǐng)你進(jìn)入源碼的世界,去探究boost::function(下文簡(jiǎn)稱function)內(nèi)部的精微結(jié)構(gòu)。
    通常 ,在單純的情況下,對(duì)函數(shù)的調(diào)用簡(jiǎn)單而且直觀,像這樣:
    int fun(int someVal);
    int main(){
    fun(10);
    }
    然而你可能需要在某個(gè)時(shí)刻將函數(shù)指針保存下來(lái),并在以后的另一個(gè)時(shí)刻調(diào)用它,像這樣:
    int fun(int);
    typedef int (*func_handle)(int);
    int main(){
    func_handle fh=fun;
    ... //do something
    fh(10);
    }
    但是,如果fun形式為void fun(int)呢?如你所見(jiàn),fun可能有無(wú)數(shù)種形式,如果對(duì)fun的每一個(gè)形式都typedef一個(gè)對(duì)應(yīng)的func_handle,則程序員會(huì)焦頭爛額,不勝其擾,代碼也可能變得臃腫和丑陋不堪,甚至如果fun是仿函數(shù)呢?
    幸運(yùn)的是C++泛型可以使代碼變得優(yōu)雅精致,面對(duì)無(wú)數(shù)種的可能,泛型是的選擇。 因此,你只是需要一個(gè)能夠保存函數(shù)指針的泛型模板類(對(duì)應(yīng)于Command模式),因?yàn)榉盒途幊逃幸粋€(gè)先天性的優(yōu)勢(shì)——可以借助編譯器的力量在編譯期根據(jù)用戶提供的型別信息化身千萬(wàn)(具現(xiàn)化),所以一個(gè)泛型的類可以有無(wú)限個(gè)具現(xiàn)體,也就是說(shuō)可以保存無(wú)限多種可能型別的函數(shù)或類似函數(shù)的東西(如,仿函數(shù))。這個(gè)類(在Boost庫(kù)中的類名為function)與函數(shù)指針相比應(yīng)該有以下一些優(yōu)勢(shì):
    ¨ 同一個(gè)function對(duì)象應(yīng)能夠接受與它形式兼容的所有函數(shù)和仿函數(shù),例如:
    int f1(int); //這是個(gè)函數(shù),形式為 int(int)
    short f2(double); //這個(gè)函數(shù)形式為 short(double)
    struct functor //這是個(gè)仿函數(shù)類,形式為int(int)
    {
    int operator()(int){}
    };
    functor f3; //創(chuàng)建仿函數(shù)對(duì)象
    boost::function<int(int)> func; // int(int)型的函數(shù)或仿函數(shù)
    func = f1; //接受f1
    func(10); //調(diào)用f1(10)
    func = f2; //也能接受short(double)型的f2
    func(10); //調(diào)用f2(10)
    func = f3; //也能接受仿函數(shù)f3
    func(10); //調(diào)用f3(10)
    ¨ function應(yīng)能夠和參數(shù)綁定以及其它function-construction庫(kù)協(xié)同工作。例如,function應(yīng)該也能夠接受std::bind1st返回的仿函數(shù)。這一點(diǎn)其實(shí)由第一點(diǎn)已經(jīng)有所保證。
    ¨ 當(dāng)接受的一個(gè)空的仿函數(shù)對(duì)象被調(diào)用的時(shí)候function應(yīng)該有可預(yù)期的行為。
    顯然,第一點(diǎn)是我們的重點(diǎn),所謂形式兼容,就是說(shuō),對(duì)于:
    R1 (T0,T1,T2,...,TN) => FunctionType1
    R2 (P0,P1,P2,...,PN) => FunctionType2
    兩種類型的函數(shù)(廣義),只要滿足:
    1. R2能夠隱式轉(zhuǎn)換為R1
    2. 所有Ti都能夠隱式轉(zhuǎn)換為Pi (i取0,1,2,...)
    那么就說(shuō),boost::function<FunctionType1>可以接受FunctionType2類型的函數(shù)(注意,反之不行)。支持這一論斷的理由是,只要Ti能夠隱式轉(zhuǎn)型為Pi,那么參數(shù)被轉(zhuǎn)發(fā)給真實(shí)的函數(shù)調(diào)用就是安全的,并且如果R2能夠隱式轉(zhuǎn)型為R1,那么返回真實(shí)函數(shù)調(diào)用所返回的值就是安全的。這里安全的含義是,C++類型系統(tǒng)認(rèn)為隱式轉(zhuǎn)換不會(huì)丟失信息,或者會(huì)給出編譯警告,但能夠通過(guò)編譯。
    后面你會(huì)看到,boost::function通過(guò)所謂的invoker非常巧妙地實(shí)現(xiàn)了這點(diǎn),并且阻止了被形式不兼容的函數(shù)賦值的操作。