要開始使用 Boost.Function, 就要包含頭文件 "boost/function.hpp", 或者某個帶數(shù)字的版本,從 "boost/function/function0.hpp" 到 "boost/function/function10.hpp". 如果你知道你想保存在 function 中的函數(shù)的參數(shù)數(shù)量,這樣做可以讓編譯器僅包含需要的頭文件。如果包含 "boost/function.hpp", 那么就會把其它的頭文件也包含進(jìn)去。 理解被存函數(shù)的最佳方法是把它想象為一個普通的函數(shù)對象,該函數(shù)對象用于封裝另一個函數(shù)(或函數(shù)對象)。這個被存的函數(shù)的最大用途是它可以被多次調(diào)用,而無須在創(chuàng)建 function 時立即使用。在聲明 functions 時,聲明中最重要的部分是函數(shù)的簽名。這部分即是告訴 function 它將保存的函數(shù)或函數(shù)對象的簽名和返回類型。我們已經(jīng)看到,有兩種方法來執(zhí)行這個聲明。這里有一個完整的程序,程序聲明了一個 boost::function ,它可以保存返回 bool (或某個可以隱式轉(zhuǎn)換為 bool 的類型)并接受兩個參數(shù)的類函數(shù)實體,第一個參數(shù)可以轉(zhuǎn)換為 int, 第二個參數(shù)可以轉(zhuǎn)換為 double. #include <iostream> 當(dāng) function f 首次創(chuàng)建時,它不保存任何函數(shù)。它是空的,可以在一個布爾上下文中進(jìn)行測試。如果你試圖調(diào)用一個沒有保存任何函數(shù)或函數(shù)對象的 function ,它將拋出一個類型 bad_function_call 的異常。為了避免這個問題,我們用普通的賦值語法把一個指向 some_func 的指針賦值給 f 。這導(dǎo)致 f 保存了到 some_func 的指針。最后,我們用參數(shù)10 (一個 int) 和 1.1 (一個 double)來調(diào)用 f (用函數(shù)調(diào)用操作符)。要調(diào)用一個 function, 你必須提供被存函數(shù)或函數(shù)對象所期望的準(zhǔn)確數(shù)量的參數(shù)。 回調(diào)的基礎(chǔ)我們先來看看在沒有 Boost.Function 以前我們?nèi)绾螌崿F(xiàn)一個簡單的回調(diào),然后再把代碼改為使用 function, 并看看會帶來什么優(yōu)勢。我們從一個支持某種簡單的回調(diào)形式的類開始,它可以向任何對新值關(guān)注的對象報告值的改變。這里的回調(diào)是一種傳統(tǒng)的C風(fēng)格回調(diào),即使用普通函數(shù)。這種回調(diào)用可用于象GUI控制這樣的場合,它可以通知觀察者用戶改變了它的值,而不需要對監(jiān)聽該信息的客戶有任何特殊的知識。 #include <iostream> 這里的兩個函數(shù),print_new_value 和 interested_in_the_change, 它們的函數(shù)簽名都兼容于 notifier 類的要求。這些函數(shù)指針被保存在一個 vector 內(nèi),并且無論何時它的值被改變,這些函數(shù)都會在一個循環(huán)里被調(diào)用。調(diào)用這些函數(shù)的一種語法是: (*vec_[i])(value_); 值(value_)被傳遞給解引用的函數(shù)指針(即 vec_[i] 所返回的)。另一種寫法也是有效的,即這樣: vec_[i](value_); 這種寫法看起來更好看些,但更為重要的是,它還可以允許你把函數(shù)指針更換為 Boost.Function 而沒有改變調(diào)用的語法。現(xiàn)在,工作還是正常的,但是,唉,函數(shù)對象不能用于這個 notifier 類。事實上,除了函數(shù)指針以外,別的任何東西都不能用,這的確是一種局限。但是,如果我們使用 Boost.Function,它就可以工作。重寫這個 notifier 類非常容易。 class notifier { 首先要做的事是,把 typedef 改為代表 boost::function 而不是函數(shù)指針。之前,我們定義的是一個函數(shù)指針;現(xiàn)在,我們使用泛型方法,很快就會看到它的用途。接著,我們把成員函數(shù) add_observer 的簽名改為泛化的參數(shù)類型。我們也可以把它改為接受一個 boost::function,但那樣會要求該類的用戶必須也知道 function 的使用方法[2],而不是僅僅知道這個觀察者類型的要求就行了。應(yīng)該注意到 add_observer 的這種變化并不應(yīng)該是轉(zhuǎn)向 function 的結(jié)果;無論如何代碼應(yīng)該可以繼續(xù)工作。我們把它改為泛型的;現(xiàn)在,不管是函數(shù)指針、函數(shù)對象,還是 boost::function 實例都可以被傳遞給 add_observer, 而無須對已有用戶代碼進(jìn)行任何改動。把元素加入到 vector 的代碼有一些修改,現(xiàn)在需要創(chuàng)建一個 boost::function<void(int)> 實例。最后,我們把調(diào)用這些函數(shù)的語法改為可以使用函數(shù)、函數(shù)對象以及 boost::function 實例
[2] 他們應(yīng)該知道 Boost.Function,但如果他們不知道呢?我們添加到接口上的任何東西都必須及時向用戶解釋清楚。 [3] 現(xiàn)在我們知道,一開始我們就應(yīng)該用這種語法。 這個函數(shù)對象保存以前的值,并在值被改變時把舊值輸出到 std::cout 。注意,當(dāng)它第一次被調(diào)用時,它并不知道舊值。這個函數(shù)對象在函數(shù)中使用一個靜態(tài) bool 變量來檢查這一點(diǎn),該變量被初始化為 true. 由于函數(shù)中的靜態(tài)變量是在函數(shù)第一次被調(diào)用時進(jìn)行初始化的,所以它僅在第一次調(diào)用時被設(shè)為 true 。雖然也可以在普通函數(shù)中使用靜態(tài)變量來提供狀態(tài),但是我們必須知道那樣不太好,而且很難做到多線程安全。因此,帶狀態(tài)的函數(shù)對象總是優(yōu)于帶靜態(tài)變量的普通函數(shù)。notifier 類并不關(guān)心這是不是函數(shù)對象,只要符合要求就可以接受。以下更新的例子示范了它如何使用。 關(guān)鍵一點(diǎn)要注意的是,我們新增的一個觀察者不是函數(shù)指針,而是一個 knows_the_previous_value 函數(shù)對象的實例。運(yùn)行這段程序的輸出如下: 在這里最大的優(yōu)點(diǎn)不是放寬了對函數(shù)的要求(或者說,增加了對函數(shù)對象的支持),而是我們可以使用帶狀態(tài)的對象,這是非常需要的。我們對 notifier 類所做的修改非常簡單,而且用戶代碼不受影響。如上所示,把 Boost.Function 引入一個已有的設(shè)計中是非常容易的。 Boost.Function 不支持參數(shù)綁定,這在每次調(diào)用一個 function 就要調(diào)用同一個類實例的成員函數(shù)時是需要的。幸運(yùn)的是,如果這個類實例被傳遞給 function 的話,我們就可以直接調(diào)用它的成員函數(shù)。這個 function 的簽名必須包含類的類型以及成員函數(shù)的簽名。換言之,顯式傳入的類實例要作為隱式的第一個參數(shù),this。這樣就得到了一個在給出的對象上調(diào)用成員函數(shù)的函數(shù)對象??匆幌乱韵逻@個類: 成員函數(shù) do_stuff 要從一個 boost::function 實例里被調(diào)用。要做到這一點(diǎn),我們需要 function 接受一個 some_class 實例,簽名的其它部分為一個 void 返回以及一個 int 參數(shù)。對于如何把 some_class 實例傳給 function,我們有三種選擇:傳值,傳引用,或者傳址。如何要傳值,代碼就應(yīng)該這樣寫[4] [4] 很少會有理由來以傳值的方式傳遞對象參數(shù)。 注意,返回類型仍舊在最開始,后跟成員函數(shù)所在的類,最后是成員函數(shù)的參數(shù)類型。它就象傳遞一個 this 給一個函數(shù),該函數(shù)暗地里用類實例調(diào)用一個非成員函數(shù)。要把函數(shù) f 配置為成員函數(shù) do_stuff, 然后調(diào)用它,我們這樣寫: 如果要傳引用,我們要改一下函數(shù)的簽名,并傳遞一個 some_class 實例。 最后,如果要傳 some_class 的指針[5],我們就要這樣寫: [5] 裸指針或智能指針皆可。 好了,所有這些傳遞"虛擬 this"實例的方法都已經(jīng)在庫中提供。當(dāng)然,這種技術(shù)也是有限制的:你必須顯式地傳遞類實例;而理想上,你更愿意這個實例被綁定在函數(shù)中。乍一看,這似乎是 Boost.Function 的缺點(diǎn),但有別的庫可以支持參數(shù)的綁定,如 Boost.Bind 和 Boost.Lambda. 我們將在本章稍后的地方示范這些庫會給 Boost.Function 帶有什么好處。 我們已經(jīng)看到,由于支持了函數(shù)對象,就可以給回調(diào)函數(shù)增加狀態(tài)??紤]這樣一個類,keeping_state, 它是一個帶狀態(tài)的函數(shù)對象。keeping_state 的實例記錄一個總和,它在每次調(diào)用操作符執(zhí)行時被增加?,F(xiàn)在,將該類的一個實例用于兩個 boost::function 實例,結(jié)果有些出人意外。 寫完這段代碼并接著執(zhí)行它,程序員可能期望保存在 ks 的總和是20,但不是;事實上,總和為0。以下是這段程序的運(yùn)行結(jié)果。 原因是每一個 function 實例(f1 和 f2)都含有一個 ks 的拷貝,這兩個實例得到的總和都是10,但 ks 沒有變化。這可能是也可能不是你想要的,但是記住,boost::function 的缺省行為是復(fù)制它要調(diào)用的函數(shù)對象,這一點(diǎn)很重要。如果這導(dǎo)致不正確的語義,或者如果某些函數(shù)對象的復(fù)制代價太高,你就必須把函數(shù)對象包裝在 boost::reference_wrapper 中,那樣 boost::function 的復(fù)制就會是一個 boost::reference_wrapper 的拷貝,它恰好持有一個到原始函數(shù)對象的引用。你無須直接使用 boost::reference_wrapper ,你可以使用另兩個助手函數(shù),ref 和 cref。 這兩函數(shù)返回一個持有到某特定類型的引用或 const 引用的 reference_wrapper。在前例中,要獲得我們想要的語義,即使用同一個 keeping_state 實例,我們就需要把代碼修改如下: boost::ref 的用途是通知 boost::function,我們想保存一個到函數(shù)對象的引用,而不是一個拷貝。運(yùn)行這個程序有以下輸出: 這正是我們想要的結(jié)果。使用 boost::ref 和 boost::cref 的不同之處就象引用與 const 引用的差異,對于后者,你只能調(diào)用其中的常量成員函數(shù)。以下例子使用一個名為 something_else 的函數(shù)對象,它有一個 const 的調(diào)用操作符。 對于這個函數(shù)對象,我們可以使用 boost::ref 或 boost::cref. 如果我們改變了 something_else 的實現(xiàn),使其函數(shù)為非const, 則只有 boost::ref 可以使用,而 boost::cref 將導(dǎo)致一個編譯期錯誤。 如果一個 function 包含一個被 boost::reference_wrapper 所包裝的函數(shù)對象,那么復(fù)制構(gòu)造函數(shù)與賦值操作就會復(fù)制該引用,即 function 的拷貝將引向原先的函數(shù)對象。 這等同于使用 boost::ref 并把函數(shù)對象 ks 賦給每一個 function 實例。 給回調(diào)函數(shù)增加狀態(tài),可以發(fā)揮巨大的能力,這也正是使用 Boost.Function 與使用函數(shù)對象相比具有的非常突出的優(yōu)點(diǎn)。 當(dāng)我們把 Boost.Function 與某個支持參數(shù)綁定的庫結(jié)合起來使用時,事情變得更為有趣。Boost.Bind 為普通函數(shù)、成員函數(shù)以及成員變量提供參數(shù)綁定。這非常適合于 Boost.Function, 我們常常需要這類綁定,由于我們使用的類本身并不是函數(shù)對象。那么,我們用 Boost.Bind 把它們轉(zhuǎn)變?yōu)楹瘮?shù)對象,然后我們可以用 Boost.Function 來保存它們并稍后調(diào)用。在將圖形用戶界面(GUIs)與如何響應(yīng)用戶的操作進(jìn)行分離時,幾乎總是要使用某種回調(diào)方法。如果這種回調(diào)機(jī)制是基于函數(shù)指針的,就很難避免對可以使用回調(diào)的類型的某些限制,也就增加了界面表現(xiàn)與業(yè)務(wù)邏輯之間的耦合風(fēng)險。通過使用 Boost.Function,我們可以避免這些事情,并且當(dāng)與某個支持參數(shù)綁定的庫結(jié)合使用時,我們可以輕而易舉地把上下文提供給調(diào)用的函數(shù)。這是本庫最常見的用途之一,把業(yè)務(wù)邏輯即從表示層分離出來。 以下例子包含一個藝術(shù)級的磁帶錄音機(jī),定義如下: 這個磁帶錄音機(jī)可以從一個GUI進(jìn)行控制,或者也可能從一個腳本客戶端進(jìn)行控制,或者從別的源進(jìn)行控制,這意味著我們不想把這些函數(shù)的執(zhí)行與它們的實現(xiàn)耦合起來。建立這種分離的一個常用的方法是,用專門的對象負(fù)責(zé)執(zhí)行命令,而讓客戶對命令如何執(zhí)行毫無所知。這也被稱為命令模式(Command pattern),并且在它非常有用。這種模式的特定實現(xiàn)中的一個問題是,需要為每個命令創(chuàng)建單獨(dú)的類。以下片斷示范了它看起來是個什么樣子: 這并不是一個非常吸引的方案,因為它使得代碼膨脹,有許多簡單的命令類,而它們只是簡單地負(fù)責(zé)調(diào)用一個對象的單個成員函數(shù)。有時候,這是必需的,因為這些命令可能需要實現(xiàn)業(yè)務(wù)邏輯和調(diào)用函數(shù),但通常它只是由于我們所使用的工具有所限制而已。這些命令類可以這樣使用: 現(xiàn)在,不用再創(chuàng)建額外的具體的命令類,如果我們實現(xiàn)的命令都是調(diào)用一個返回 void 且沒有參數(shù)(先暫時忽略函數(shù) record, 它帶有一個參數(shù))的成員函數(shù)的話,我們可以來點(diǎn)泛化。不用再創(chuàng)建一組具體的命令,我們可以在類中保存一個指向正確成員函數(shù)的指針。這是邁向正確方向[6]的一大步,就象這樣: [6] 雖然損失了一點(diǎn)效率。 這個命令模式的實現(xiàn)要好多了,因為它不需要我們再創(chuàng)建一組完成相同事情的獨(dú)立的類。這里的不同在于我們保存了一個 tape_recorder 成員函數(shù)指針在 func_ 中,它要在構(gòu)造函數(shù)中提供。命令的執(zhí)行部分可能并不是你要展現(xiàn)給你的朋友看的東西,因為成員指針操作符對于一些人來說可能還不太熟悉。但是,這可以被看為一個低層的實現(xiàn)細(xì)節(jié),所以還算好。有了這個類,我們可以進(jìn)行泛化處理,不再需要實現(xiàn)單獨(dú)的命令類。 你可能還沒有理解,我們已經(jīng)在開始實現(xiàn)一個簡單的 boost::function 版本,它已經(jīng)可以做到我們想要的。不要重復(fù)發(fā)明輪子,讓我們重點(diǎn)關(guān)注手邊的工作:分離調(diào)用與實現(xiàn)。以下是一個全新實現(xiàn)的 command 類,它更容易編寫、維護(hù)以及理解。 通過使用 Boost.Function,我們可以立即從同時兼容函數(shù)和函數(shù)對象——包括由綁定器生成的函數(shù)對象——的靈活性之中獲益。這個 command 類把函數(shù)保存在一個返回 void 且不接受參數(shù)的 boost::function 中。為了讓這個類更加靈活,我們提供了在運(yùn)行期修改函數(shù)對象的方法,使用一個泛型的成員函數(shù),set_function. 通過使用泛型方法,任何函數(shù)、函數(shù)對象,或者綁定器都兼容于我們的 command 類。我們也可以選擇把 boost:: function 作為參數(shù),并使用 function 的轉(zhuǎn)型構(gòu)造函數(shù)來達(dá)到同樣的效果。這個 command 類非常通用,我們可以把它用于我們的 tape_recorder 類或者別的地方。與前面的使用一個基類與多個具體派生類(在那里我們使用指針來實現(xiàn)多態(tài)的行為)的方法相比,還有一個額外的優(yōu)點(diǎn)就是,它更容易管理生存期問題,我們不再需要刪除命令對象,它們可以按值傳遞和保存。我們在布爾上下文中使用 function f_ 來測試命令是否可用。如果函數(shù)不包含一個目標(biāo),即一個函數(shù)或函數(shù)對象,它將返回 false, 這意味著我們不能調(diào)用它。這個測試在 execute 的實現(xiàn)中進(jìn)行。以下是使用我們這個新類的一個例子: 為了創(chuàng)建一個具體的命令,我們使用 Boost.Bind 來創(chuàng)建函數(shù)對象,當(dāng)通過這些對象的調(diào)用操作符進(jìn)行調(diào)用時,就會調(diào)用正確的 tape_recorder 成員函數(shù)。這些函數(shù)對象是自完備的;它們無參函數(shù)對象,即它們可以直接調(diào)用,無須傳入?yún)?shù),這正是 boost::function<void()> 所表示的。換言之,以下代碼片斷創(chuàng)建了一個函數(shù)對象,它在配置好的 tape_recorder 實例上調(diào)用成員函數(shù) play 。 通常,我們不能保存 bind 所返回的函數(shù)對象,但由于 Boost.Function 兼容于任何函數(shù)對象,所以它可以。 注意,這個類也支持調(diào)用 record, 它帶有一個類型為 const std::string& 的參數(shù),這是由于成員函數(shù) set_function. 因為這個函數(shù)對象必須是無參的,所以我們需要綁定上下文以便 record 仍舊能夠獲得它的參數(shù)。當(dāng)然,這是綁定器的工作。因而,在調(diào)用 record 之前,我們創(chuàng)建一個包含被錄音的字符串的函數(shù)對象。 執(zhí)行這個保存在 record 的函數(shù)對象,將在 tape_recorder 實例 tr 上執(zhí)行 tape_recorder::record,并傳入字符串。有了 Boost.Function 和 Boost.Bind, 就可以實現(xiàn)解耦,讓調(diào)用代碼對于被調(diào)用代碼一無所知。以這種方式結(jié)合使用這兩個庫非常有用。你已經(jīng)在這個 command 類中看到了,現(xiàn)在我們該清理一下了。由于 Boost.Function 的杰出功能,你所需的只是以下代碼: 與 Boost.Function 兼容于由 Boost.Bind 創(chuàng)建的函數(shù)對象一樣,它也支持由 Boost.Lambda 創(chuàng)建的函數(shù)對象。你用 Lambda 庫創(chuàng)建的任何函數(shù)對象都兼容于相應(yīng)的 boost::function. 我們在前一節(jié)已經(jīng)討論了基于綁定的一些內(nèi)容,使用 Boost.Lambda 的主要不同之處是它能做得更多。我們可以輕易地創(chuàng)建一些小的、無名的函數(shù),并把它們保存在 boost::function 實例中以用于后續(xù)的調(diào)用。我們已經(jīng)在前一章中討論了 lambda 表達(dá)式,在那一章的所有例子中所創(chuàng)建的函數(shù)對象都可以保存在一個 function 實例中。function 與創(chuàng)建函數(shù)對象的庫的結(jié)合使用會非常強(qiáng)大。 有一句諺語說,世界上沒有免費(fèi)的午餐,對于 Boost.Function 來說也是如此。與使用函數(shù)指針相比,使用 Boost.Function 也有一些缺點(diǎn),特別是對象大小的增加。顯然,一個函數(shù)指針只占用一個函數(shù)指針的空間大小(這當(dāng)然了!),而一個 boost::function實例占的空間有三倍大。如果需要大量的回調(diào)函數(shù),這可能會成為一個問題。函數(shù)指針在調(diào)用時的效率也稍高一些,因為函數(shù)指針是被直接調(diào)用的,而 Boost.Function 可能需要使用兩次函數(shù)指針的調(diào)用。最后,可能在某些需要與C庫保持后向兼容的情形下,只能使用函數(shù)指針。 雖然 Boost.Function 可能存在這些缺點(diǎn),但是通常它們都不是什么實際問題。額外增加的大小非常小,而且(可能存在的)額外的函數(shù)指針調(diào)用所帶來的代價與真正執(zhí)行目標(biāo)函數(shù)所花費(fèi)的時間相比通常都是非常小的。要求使用函數(shù)而不能使用 Boost.Function 的情形非常罕見。使用這個庫所帶來的巨大優(yōu)點(diǎn)及靈活性顯然超出這些代價。 至少了解一下這個庫如何工作的基礎(chǔ)知識是非常值得的。我們來看一下保存并調(diào)用一個函數(shù)指針、一個成員函數(shù)指針和一個函數(shù)對象這三種情形。這三種情形是不同的。要真正看到 Boost.Function 如何工作,只有看源代碼——不過我們的做法有些不同,我們試著搞清楚這些不同的版本究竟在處理方法上有些什么不同。我們也有一個不同要求的類,即當(dāng)調(diào)用一個成員函數(shù)時,必須傳遞一個實例的指針給 function1 (這是我們的類的名字)的構(gòu)造函數(shù)。function1 支持只有一個參數(shù)的函數(shù)。與 Boost.Function 相比一個較為寬松的投條件是,即使是對于成員函數(shù),也只需要提供返回類型和參數(shù)類型。這個要求的直接結(jié)果就是,構(gòu)造函數(shù)必須被傳入一個類的實例用于成員函數(shù)的調(diào)用(類型可以自動推斷)。 我們將要采用的方法是,創(chuàng)建一個泛型基類,它聲明了一個虛擬的調(diào)用操作符函數(shù);然后,從這個基類派生三個類,分別支持三種不同形式的函數(shù)調(diào)用。這些類負(fù)責(zé)所有的工作,而另一個類,function1, 依據(jù)其構(gòu)造函數(shù)的參數(shù)來決定實例化哪一個具體類。以下是調(diào)用器的基類,invoker_base. 接著,我們開始定義 function_ptr_invoker, 它是一個具體調(diào)用器,公有派生自 invoker_base. 它的目的是調(diào)用普通函數(shù)。這個類也接受兩個類型,即返回類型和參數(shù)類型,它們被用于構(gòu)造函數(shù),構(gòu)造函數(shù)接受一個函數(shù)指針作為參數(shù)。 這個類模板可用于調(diào)用任意一個接受一個參數(shù)的普通函數(shù)。調(diào)用操作符簡單地以給定的參數(shù)調(diào)用保存在 func_ 中的函數(shù)。請注意(的確有些奇怪)聲明一個保存函數(shù)指針的變量的那行代碼。 你也可以用一個 typedef 來讓它好讀一些。 接著,我們需要一個可以處理成員函數(shù)調(diào)用的類模板。記住,它要求在構(gòu)造時給出一個類實例的指針,這一點(diǎn)與 Boost.Function 的做法不一樣。這樣可以節(jié)省我們的打字,因為是編譯器而不是程序員來推導(dǎo)這個類。 這個類模板與普通函數(shù)指針的那個版本很相似。它與前一個版本的不同在于,構(gòu)造函數(shù)保存了一個成員函數(shù)指針與一個對象指針,而調(diào)用操作符則在該對象(t_)上調(diào)用該成員函數(shù)(func_)。 最后,我們需要一個兼容函數(shù)對象的版本。這是所有實現(xiàn)中最容易的一個,至少在我們的方法中是這樣。通過使用單個模板參數(shù),我們只表明類型 T 必須是一個真正的函數(shù)對象,因為我們想要調(diào)用它。說得夠多了。 現(xiàn)在我們已經(jīng)有了這些適用的積木,剩下來的就是把它們放在一起組成我們的自己的 boost::function, 即 function1 類。我們想要一種辦法來發(fā)現(xiàn)要實例化哪一個調(diào)用器。然后我們可以把它存入一個 invoker_base 指針。這里的竊門就是,提供一些構(gòu)造函數(shù),它們有能力去檢查對于給出的參數(shù),哪種調(diào)用器是正確的。這僅僅是重載而已,用了一點(diǎn)點(diǎn)手法,包括泛化兩個構(gòu)造函數(shù)。 如你所見,這里面最難的部分是正確地定義出推導(dǎo)系統(tǒng)以支持函數(shù)指針、類成員函數(shù)以及函數(shù)對象。無論使用何種設(shè)計來實現(xiàn)這類功能的庫,這都是必須的。最后,給出一些例子來測試我們這個方案。 我們的 function1 類可以接受以下所有函數(shù)。 它也可以使用象 Boost.Bind 和 Boost.Lambda 這樣的 binder 庫所返回的函數(shù)對象。我們的類與 Boost.Function 中的類相比要簡單多了,但是也已經(jīng)足以看出創(chuàng)建和使用這樣一個庫的問題以及相關(guān)解決方法。知道一點(diǎn)關(guān)于一個庫是如何實現(xiàn)的事情,對于有效使用這個庫是非常有用的。 |
|