2012-07-11 220 views
2

假設我想創建一個作用於某種常規類型的函子。 例如C模板仿函子。類模板vs函數模板

template<typename Ape> 
class functor1 
{ 
    void operator()(Ape& m) 
    { 
     // Do something to m 
    } 
}; 

這一直是我做事的標準方式。但是,我也有另一種方法:

class functor2 
{ 
    template<typename Ape> 
    void operator()(Ape& m) 
    { 
     // Do something to m 
    } 
}; 

第二種方法的優點是我不必明確說明模板的類型。

int main() 
{ 
    std::vector<chimpanzee> chimps(100); 
    for_each(chimps.begin(), chimps.end(), functor1<chimpanzee>()); // Explicity state the type 
    for_each(chimps.begin(), chimps.end(), functor2()); // Less typing. Will it work? 
} 

第二個版本會工作嗎?或者我錯過了什麼?如果它起作用,第一種方法有什麼優勢?

+1

你試過這個嗎? – 2012-07-11 14:21:15

回答

3

明顯的區別在於,在第一種情況下,您明確指定了類型,而在第二種情況下,編譯器會在實際調用的上下文中爲您推導出類型。但是,在你的具體例子中,它可能根本就沒有真正的區別。

  1. 如果你的類必須在它的多個成員函數,第一個變種會「修正」爲所有這些相同的模板參數,而在第二個變體的參數將被獨立推導出每一個成員函數。

    從多個上下文中調用單個成員函數時也是如此:每個上下文將在第二個變體中執行自己的模板參數推演。

    這可能是好的或不是很好,這取決於你的意圖。

  2. 如果函數通過值(或const引用)接受了它的參數,則在第一個變體中,可以爲參數指定與存儲在容器中的參數不同的類型。例如,您可以創建一個函數long並將其應用於容器int s。這在第二個變體中是不可能的。

    例如,如果您的chimpanzee類是多態的,從animal派生,則可以使用functor1<animal>來遍歷此容器。在第二個變體中,模板參數將被推斷爲chimpanzee,而不是animal

  3. 如果您的類有數據成員,則第二個變體將確保成員函數的所有特化都共享相同的數據(如果使用相同的函子對象)。在第一個變體中,每個專業化是一個不同的類,它獲得自己的數據。

+0

不確定最後一部分。如果所述數據被聲明爲「靜態」或者在所有情況下使用相同的對象,則專業化只會共享相同的數據。如果使用不同的函數對象,並且成員不是「靜態」,那麼就沒有共享數據。 – 2012-07-11 14:31:20

+1

@Mike DeSimone:我指的是*模板成員函數*在同一個非模板對象上調用的所有特化。當然,他們會分享數據。這只是很難表達清楚... – AnT 2012-07-11 14:36:47

+0

謝謝你的非常詳細的答案。 – Iam 2012-07-11 16:16:16

1

對於沒有狀態的仿函數,這應該是相同的。經常(比較)你需要在仿函數中存儲另一個相同類型的object/ref/pointer,而你的第二個選項在這種情況下不起作用。請注意,如果您的仿函數確實需要構造函數參數,您可以使用免費函數make_<foo>(如make_pair)來推導出您的類型,並再次減少鍵入。

+0

請給我一個'make_ '的例子嗎?我不太明白我如何使用這樣的功能。 – Iam 2012-07-11 16:14:53

1

這就像作用域:在functor1,在課堂上什麼都可以使用類型Ape(爲成員聲明,​​參數和返回類型的類型,特點,或其他),而在functor2Ape不僅意味着內的東西範圍爲operator()。總之:

  • 時定義:
    • functor1需要了解Ape當它是創建
    • functor2不需要知道Ape,直到它調用
  • 範圍類型:
    • functor1一切都知道Ape
    • 只有operator()functor2知道Ape
  • 多功能性的實例:
    • 一個functor1實例只適用於單一類型的Ape
    • A functor2實例適用於任何類型的Ape
+0

我不知道如果functor1「是一個」猿:),但我明白你的意思。謝謝您的回答。 – Iam 2012-07-11 16:17:51

+0

你說得對,那有點關閉。如果你將它聲明爲'template class functor1:public Ape {...};'我會澄清我的答案。 – 2012-07-11 22:29:27