函數對象與高級編程
千萬不要忘記,在C++中,最好不要只從語言本身來判定,它被設計為可以通過庫來彌補本身的缺點
Bind成功的一個關鍵是采用統一的語法來創建函數對象,以及對應于使用該庫的類型只有很少的要求。這種設計使得無需關注如何去寫與你的類型一起工作的代碼,而只需關注我們最關心的一點,代碼如何工作以及它實際上做了什么。
弄明白如何使用bind的關鍵是,占位符的概念。占位符用于表示提供給結果函數對象的參數,Boost.Bind支持最多九個參數。占位符被命名為_1,_2,直至_9,你要把它們放在你原先放參數的地方。
普通函數與成員函數之間有著非常大的差異,在綁定一個成員函數時,bind表達式的第一個參數必須是成員函數所在類的實例!理解這個規則的最容易的方法是,這個顯式的參數將取代隱式的this,被傳遞給所有的非靜態成員函數。
bind總是執行復制。如果你通過值來傳遞,對象將被復制,這可能對性能有害或者產生不必要的影響。為了避免復制對象,你可以使用boost::ref/boost::cref或者使用指針語義。
正如我們所看到的,沒有一個明顯的方法來保存我們的綁定器以備后用,我們只知道它們是帶有某些(未知)的特征的兼容函數對象。但是,如果使用 Boost.Function, 保存函數用于以后的調用正是那個庫要做的,并且它兼容于 Boost.Bind, 可以把綁定器賦值給函數,保存它們并用于以后的調用。這是一個非常有用的概念,它可以用于適配并提高了松耦合。
Lambda 庫
Boost.Lambda可以創建直接定義和調用的函數對象,或者把它保存起來晚一些再調用。這與Boost.Bind庫所提供的很相似,但Boost.Lambda除了可以進行參數綁定,還有其他功能,增加了控制結構、表達式到函數對象的自動轉換,還支持在Lambda表達式中的異常處理。
Lambda庫用于解決一個使用標準庫算法時常會遇見的問題,即需要為了滿足算法的要求而定義很多簡單的函數對象。
Function 庫
保存函數指針和函數對象,用于后續的調用
boost::function 的缺省行為是復制它要調用的函數對象,這一點很重要。如果這導致不正確的語義,或者如果某些函數對象的復制代價太高,你就必須把函數對象包裝在 boost::reference_wrapper 中,那樣 boost::function 的復制就會是一個 boost::reference_wrapper 的拷貝,它恰好持有一個到原始函數對象的引用。你無須直接使用 boost::reference_wrapper ,你可以使用另兩個助手函數,ref 和 cref。 這兩函數返回一個持有到某特定類型的引用或 const 引用的 reference_wrapper。
代價的考慮:與使用函數指針相比,使用 Boost.Function 也有一些缺點,特別是對象大小的增加。顯然,一個函數指針只占用一個函數指針的空間大小(這當然了!),而一個 boost::function實例占的空間有三倍大。函數指針在調用時的效率也稍高一些,因為函數指針是被直接調用的,而 Boost.Function 可能需要使用兩次函數指針的調用。最后,可能在某些需要與C庫保持后向兼容的情形下,只能使用函數指針。
與使用函數指針相比,使用 Boost.Function 有幾個優點:通過兼容的函數對象而不是真實的簽名放松了對簽名的要求;可以使用綁定器,如 Boost.Bind 和 Boost.Lambda;可以在調用函數之前檢測函數是否為空,即是否存在目標函數;可以使用帶狀態的對象而不僅限于無狀態函數。這些優點表明了使用 Boost.Function 替代C風格的回調可以解決這類普遍存在的問題。使用 Boost.Function 比使用函數指針要多付出一點點代價,只有這一點小代價是被禁止時,才應該考慮使用函數指針技術。
Signals庫
函數和函數對象的靈活多點回調
健壯的觸發器及事件處理的機制
兼容于函數對象工廠,如Boost.Bind和Boost.Lambda
Boost.Signals庫具體化了信號(signals)和插槽(slots),信號指的是某種可被“拋出”的東西,而插槽是接收該信號的連接者。