2012-04-29 154 views
8

關於CRP如果我要實現它(使用模板的模板參數)有輕微的變化,我得到一個編譯錯誤:奇怪的循環模板 - 變化

template <template <typename T> class Derived> 
class Base 
{ 
public: 
    void CallDerived() 
    { 
     Derived* pT = static_cast<Derived*> (this); 
     pT->Action(); // instantiation invocation error here 
    } 
}; 

template<typename T> 
class Derived: public Base<Derived> 
{ 
public: 
    void Action() 
    { 
    } 
}; 

我不完全相信人會選擇這種形式(無法編譯對我來說),而不是使用這雖然(這個工程)

template <typename Derived> 
class Base 
{ 
public: 
    void CallDerived() 
    { 
     Derived* pT = static_cast<Derived*> (this); 
     pT->Action(); 
    } 
}; 

template<typename T> 
class Derived: public Base<Derived<T>> 
{ 
public: 
    void Action() 
    { 
    } 
}; 

回答

11

這也應該編譯。我們只需要得到明確指定其他模板參數

template <typename T, template <typename T> class Derived> 
class Base 
{ 
public: 
    void CallDerived() 
    { 
     Derived<T>* pT = static_cast<Derived<T>*> (this); 
     pT->Action(); // instantiation invocation error here 
    } 
}; 

template<typename T> 
class Derived: public Base<T,Derived> 
{ 
public: 
    void Action() 
    { 
    } 
}; 
+1

非常有趣的一個必須在聲明中明確指出typename T兩次...不明白爲什麼 – Ghita

+1

剛剛意識到派生必須傳遞它的T參數。 – Ghita

5

在第一個例子中,類模板,其實需要模板的模板參數,不只是模板參數,因爲你寫的:

template <template <typename T> class Derived> 
class Base 
{ 
    //.. 
}; 

所以這個代碼是沒有意義的:

Derived* pT = static_cast<Derived*> (this); 
pT->Action(); // instantiation invocation error here 

這裏Derived是一個模板,模板參數,它需要你沒有模板參數提供給它。事實上,在CallDerived()函數中,您無法知道需要提供給它的類型,以便執行您打算執行的操作。

第二種方法是正確的解決方案。用它。

+1

但我怎麼提供模板參數在第一種情況下..使用衍生 * PT無法正常工作或 – Ghita

+1

@Ghita:'T'沒有已知基類。其他解決方案已經解釋瞭如何將'T'傳遞給基地。但這不是必要的,因爲你應該去尋找第二個解決方案。 – Nawaz

+1

有時在基類中需要T。例如。當有一個成員'T Action();'當然,你可以使用一個traits類爲每個Derived類提供一個T,但有時候你希望T和Derived獨立變化。在這種情況下,您需要使用模板+模板參數的[第一種]方法。 – TemplateRex