第十六章 string類和標準模板庫(5)函數對象

(五)函數對象

函數對象,也叫作函數符functor。函數符是可以以函數的方式與()結合的任意對象,包括函數名,函數指針,重載了()運算符的類對象(也就是定義了比如double operator()(double)成員函數的類)。

前面介紹了for_each()函數,可以使用函數對象作爲第三個參數來對每個迭代器指向的元素進行處理,比如for_each(dice.begin(),dice.end(),Show);其中Show就可以是任意一種形式的函數對象(函數符)。第三個參數可以是常規函數,也可以是函數符。實際上,for_each()函數是一個模板函數,前兩個參數是迭代器,用以指定相應的容器的範圍,通過輸入具體的容器,模板也具體化爲相應的函數,第三個參數也是一個模板類型符號,通過輸入函數符,可以將函數的信息(返回值以及參數列表)告訴函數模板,從而具體化爲相應的類。

1.函數符的概念

正如STL定義了容器和迭代器的概念一樣,它也定義了函數符的概念。

生成器generator是不用參數就可以調用的函數符;一元函數unary function是隻有一個參數的函數符;二元函數binary function是有兩個參數的函數符。例如,提供給for_each()函數的函數符應該是一個一元函數符,因爲它每次只處理容器中的一個元素。

這些概念都有相應的改進版本(上面的都是概念,前面講過概念,改進和模型的關係),返回bool的一元函數predicate謂詞返回bool的二元函數是binary predicate二元謂詞。可以使用類模板將兩個參數的謂詞函數轉換爲一個參數的謂詞函數,其中一個參數被用作類的構造參數而隱式傳遞給函數符,從而可以作爲函數適配器,適應不同的參數類型(就是說使用類模板將binary predicate轉換爲一個函數類對象,用我們需要的值構造這個類對象,這個值就是原來二元函數的一個參數,這樣新的類對象可以作爲一元函數符來使用了,調用的時候再給定第二個參數)。總之,兩個參數的函數被轉換成了單參數的函數對象,因此類函數符可以作爲一個函數適配器,來將多參數的函數轉換成單參數的函數,以適應不同的需求。

2.預定義的函數符

STL定義了許多基本函數符,提供這些函數對象是爲了支持將函數作爲參數的STL函數。STL在頭文件<functional>中定義了許多函數模板類,可以支持很多的運算,比如plus<>就是將兩個參數相加的函數符,當實例化以後,比如plus<double> xx;則xx就像普通的二元函數那樣使用就可以了。

其他的函數還有很多,大部分是對算術運算符的模板化,比如-是minus,*是multiplies,/是divides,>=是greater_equal等等。

3.自適應函數符和函數適配器

自適應函數符是指攜帶了標識參數類型和返回類型的typedef成員(也即是說我們可以調用這些成員,從而可以知道函數模板具體化之後的相應的參數和返回值的類型)。這些成員分別是result_type,first_argument_type和second_argument_type。自適應的意思就是可以通過查看來適應程序環境,這種特性被用作將二元函數轉換爲一元函數等場景中,相當於函數的適配,只不過這種適配是自動進行的,如binder1st(f2,val)f1;f1(x);就相當於先定義了一個函數對象,將第一個參數加進去,這個函數對象就可以再調用第二個參數,總體的作用就像調用了f2(val,x)的效果。

c++11提供了函數指針和函數符的替代品,拉姆達表達式。這將在後面討論。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章