2011-01-19 49 views
3

考慮下面的代碼:語法爲模板的成員函數

template <typename Datatype> 
class MyClass 
{ 
    void doStuff(); 

    template <typename AnotherDatatype> 
    void doTemplateStuff(AnotherDatatype Argument); 
}; 

template <typename Datatype> 
void MyClass<Datatype>::doStuff() 
{ 
    // ... 
} 

template <typename Datatype> 
template <typename AnotherDatatype> 
void MyClass<Datatype>::doTemplateStuff(AnotherDatatype Argument) 
{ 
    // ... 
} 

的第二個成員函數,doTemplateStuff的實施,將無法編譯,如果我凝結像這樣:

template <typename Datatype, typename AnotherDatatype> 
void MyClass<Datatype>::doTemplateStuff(AnotherDatatype Argument) 
{ 
    // ... 
} 

這是爲什麼?不應該用逗號分隔模板信息與將每個typename放在同一行上的效果相同?還是有一些細微的差別,我不知道...?

(另外,如果有人能想到更好的標題請讓我知道。)

回答

3

這是一個非常好的問題。我不知道標準委員會決定如何設計模板的具體原因,但我認爲這是對lambda演算和類型理論的回調。從數學上講,任何帶有兩個參數並返回一個值的函數和一個接受單個參數的函數之間存在同構,然後返回一個接受另一個參數並返回值的函數。例如:

&lambda; x。 &拉姆達; Y。 X + Y

同構與(但不完全相同)

&拉姆達;(X,Y)。 x + y

其中(x,y)是表示x和y對的單個對象。

使用C++成員函數模板,C++選擇使用這些系統中的第一個。您必須爲最外層函數指定所有參數,然後分別指定最內層函數的所有參數。在數學上,這相當於在一個參數列表中同時指定所有參數,但C++沒有選擇這樣做。

現在,一個非常好的問題是爲什麼他們沒有這樣做。我不完全確定理由,但如果我不得不猜測這是因爲模板專業化的奇怪的互動。如果我能想到一些具體的東西,我會更新這篇文章。

+2

這種同構稱爲Currying(參見http://en.wikipedia.org/wiki/Currying)。例如,它是Haskell編程語言的構建磚之一。 – 2011-01-19 07:39:16

2

把逗號的模板聲明之間告知編譯器期望兩個模板參數。在你的情況下,因爲當你聲明函數時該對象是一個模板對象,所以你違反了你自己的聲明。它正在尋找MyClass對象中的第二個模板,引用實際的類聲明並意識到這是一個錯誤。

因此,

template<typename T, typename V> 
struct Foo{ 
    void bar(); 
}; 

template<typename T, typename V> 
void Foo<T,V>::bar(){...} 

就是它的期待看到。

template<typename T> 
struct Foo{ 
    void bar(); 
} 

template<typename T, typename V> 
void Foo<T>::bar(){...} 

是錯誤。它想知道其他模板參數來自哪裏。

如果你想這樣做,你需要寫函數就在那裏:

template<typename T> 
struct Foo{ 
    template<typename V> 
    void bar(const V& _anInputValue){ 
     cout << _anInputValue; 
    } 

    void baz(); 
}; 

template<typename T> 
void Foo<T>::baz(){ 
    cout << "Another function."; 
}