2009-10-06 111 views
1

我想知道是否有人可以用函子幫我。我真的不明白函數是什麼以及它們是如何工作的我試着用Google搜索它,但我仍然沒有得到它。仿函數是如何工作的以及它們如何與模板配合使用C++模板仿函數

回答

6

仿函數基本上是一個「函數對象」。這是一個單獨的函數,你已經包裝在一個類或結構中,並且可以傳遞給其他函數。

他們通過創建自己的類或結構來重載函數調用操作符(稱爲operator())來工作。通常,通過簡單地將它構造爲函數的參數來創建它的一個實例,該函數需要一個函子。

假設你有以下幾點:

std::vector<int> counts; 

現在,你要增加所有包含該矢量計數。你可以通過手動循環來增加它們,或者你可以使用一個仿函數。合適的仿函數,在這種情況下,應該是這樣的:現在

struct IncrementFunctor 
{ 
    int operator() (int i) 
    { 
     return i + 1; 
    } 
} 

IncrementFunctor是一個仿函數這需要任意整數,並增加它。要將其應用於計數,您可以使用std :: transform函數,該函數將函子作爲參數。

std::transform(
    counts.begin(),  // the start of the input range 
    counts.end(),   // the end of the input range 
    counts.begin(),  // the place where transform should place new values. 
          // in this case, we put it right back into the original list. 
    IncrementFunctor()); // an instance of your functor 

語法IncrementFunctor()創建函子,然後將其直接傳遞到std ::變換的一個實例。當然,您可以創建一個實例作爲局部變量並將其傳遞,但​​這樣更方便。

現在,到模板上。 std :: transform中函子的類型是一個模板參數。這是因爲std :: transform不知道(或關心!)你函子的類型。它所關心的是,它有一個合適的運營商()定義,它可以這樣做

newValue = functor(oldValue); 

編譯器是非常聰明的模板,往往可以找出自身的模板參數是什麼。在這種情況下,編譯器會自動實現您傳遞的類型爲IncrementFunctor的參數,該參數在std :: transform中定義爲模板類型。它爲列表中的相同,也因此編譯器會自動識別出實際調用是這樣的:

std::transform<std::vector<int>::iterator, // type of the input iterator 
       std::vector<int>::iterator, // type of the output iterator 
       IncrementFunctor>(   // type of your functor 
    counts.begin(),  // the start of the input range 
    counts.end(),   // the end of the input range 
    counts.begin(),  // the place where transform should place new values. 
          // in this case, we put it right back into the original list. 
    IncrementFunctor()); // an instance of your functor 

它可以節省你不少打字。 )

5

函子是一些可以被調用/被叫與函數調用操作,語法上通過附加(),任選括號內的參數列表。

這就是所有模板的需求。就模板而言,它被調用的東西是允許這種語法的任何東西 - 換句話說,可以是自由函數或覆蓋operator()()的類的實例。 (一個「free」函數只是一個不是成員的函數,也就是說,它是全局作用域的函數,或者是以前包含的名稱空間範圍的函數。)

外模板元編程的,我們通常不說,一個自由的功能是AA函子,並保留該名稱爲覆蓋operator()()一個類的實例:

struct Foo { 
public: 
    void operator()(int i) { // do something } 
    void operator()(int i, char x) { // do something else } 
} 

在C++模板編譯,所以只要在語法有道理,編譯器會很樂意用一個函數或仿函數:

template<typename T> class Bar { 
    private int j ; 
    public: 
    Bar(int i) : j(i) {} 
    void doIt(T t) { 
    t(j) ; 
    } 
} 

Foo f; 
extern void resize(int i) ; // in some header 

Bar<Foo> bf(5) ; 
// a Bar that is templated on Foo 
Bar< void (&)(int) > br(5) ; 
// a Bar that is templated on a function taking int and returning void 

br.doit(&resize) ; // call resize with br.j 
bf.doit(f) ; // call Foo::operator()(int) on Foo f with bf.j 
+0

+1,一個更好的答案,因爲你確實表現出_templated_仿函數的例子。 – 2009-10-06 23:51:36

+0

雖然這個'void(&(int))'語法怎麼了?這個用法至少不是C++。它是C++/CLI嗎? 「 – 2009-10-06 23:57:54

+0

」這個void(&(int))語法怎麼了?「?是的,這是「一個函數的地址int和返回void」的錯誤。 – tpdi 2009-10-07 00:48:27