2011-08-29 21 views
0

CRTP相關的編譯器錯誤我有相當簡單的,我想,問題大概CRTP,但我似乎無法找到一個答案。可能是因爲它太簡單了,沒有人想過要問它。我對這個概念很陌生,所以請不要太難過;)。上的typedef

下面是代碼(它的排序試圖做一些類似STL容器東西):如果我評論違規typedef typename _THelpee::T Th;

template< typename tT > 
struct TBase 
{ 
    typedef tT T; 
}; 

template< typename tTBase > 
struct TTraitsBase 
{ 
    typedef typename tTBase::T T; 
}; 

template< typename tTHelpee, typename tTTraits > 
struct THelper 
{ 

    typedef typename tTTraits::T T; 
    typedef typename tTHelpee::T Th; /* This generates a compiler error: 
             'T' not being a member of TDerived<tT> */ 
    T Foo(void) 
    { 
    return static_cast< tTHelpee* > (this)->mVal; 
    } 
}; 

template< typename tT > 
struct TDerived : TBase<tT> , THelper< TDerived<tT> , TTraitsBase< TBase<tT> > > 
{ 
using TBase<tT>::T; 
    T mVal; 
}; 

int main() 
{ 
TDerived<int>::T lTmp = -1; 
TDerived<int> lObj; 

lObj.mVal = -1; 
std::cout << lObj.Foo() << std::endl; 

return 0; 
} 

一切編譯。這是什麼讓我困惑:如果編譯器不喜歡typedef typename _THelpee::T Th;,爲什麼它讓通過static_cast< _THelpee* > (this)->mVal?我認爲,它有事情做與不能夠實例TDerived何時實例THelper,但沒有清晰的認識。請問有人能給出一個簡短的解釋和/或一些有關這裏發生的事情的參考嗎?謝謝。

編輯:刪除 '_T' 前綴。

+2

標識符開始與[_和後跟大寫字母被保留(http://stackoverflow.com/questions/228783/what-are-the-rules-about-using-an-underscore-in-ac -identifier/228797#228797)。 – Flexo

+0

不要使用下劃線資本爲自己的標識符,這是禁止的。 –

回答

2

隱式實例化一個類沒有實例化它的成員函數的定義。類模板的每個成員僅在使用時才被實例化(除非使用顯式實例化)。

您隱式實例化的第一件事是TDerived<int>,在main的第一行。爲了實例化,編譯器查找TDerived模板,發現有一些依賴的基類,因此試圖實例化這些基類。 TBase<int>實例化沒有問題。但試圖實例化THelper< TDerived<int>, TTraitsBase< TBase<int> > >時,試圖獲得成員TDerived<int>::T,但TDerived<int>仍然是一個不完整的類型。

實例化THelper<...>還指出存在成員函數int Foo(),但不評估其定義的語義。

通過您從main調用lObj.Foo()的時候,它實例化int THelper<...>::Foo()TDerived<int>是一個完整的類型,所以沒有問題存在。

+0

謝謝!這清楚地解釋了它。我顯然不喜歡函數實例化序列。我沒有意識到,'TDerived'確實是不完整的,但可以弄清楚爲什麼'美孚()'沒有引起在這種情況下任何問題。現在很明顯。 – lapk

+0

在一個側面說明,它被認爲是正常使用'TTraits'或可能'TBase'模板參數'THelper'以訪問在'TDerived'那些'typedefs'?或者是否有更多的「標準」方式來做到這一點(關於這個問題的參考將不勝感激)?並再次感謝您先前的解釋。 – lapk

2

沒有與發佈的代碼夫婦的問題。既然,我無法弄清楚意圖,我會列出我發現的錯誤。

(1)使用的不完整的類型

template< typename _T > 
struct TDerived : TBase<_T> , THelper< TDerived<_T> , TTraitsBase< TBase<_T> > > 
             ^^^^^^^^^^^^^^ it's incomplete 

IMO當你定義的TDerived<_T>身體,你不應該使用相同的作爲參數傳遞給任何東西。

(2)不當類型定義。

using TBase<_T>::T; 

應該是,

typedef typename TBase<_T>::T T; 
+1

沒事了一個模板參數是一個不完整的類型(而這始終與CRTP的情況下)。但是與所有不完整的類型一樣,該類型的有效使用也存在限制。 – aschepler

+0

感謝您的輸入,iammilind。我認爲,aschepler回答了它。我不願意違反規則並進入討論,因爲我是新來的。 – lapk

1

我說你有你的CRTP循環依賴(如一個會的,就其本質而言),但是這意味着,基本模板類ISN不允許使用使用其任何參數類,因爲該參數類尚未定義 - 在Base<T>實例化時,它仍然是不完整的類型。

所以,這是確定:

template <typename T> struct Base 
{ 
    T * impl; // incomplete type is OK 
}; 

class Foo : public Base<Foo> { /* ... */ }; 

但是,這並不:

template <typename T> struct Base 
{ 
    T x; // need to know T, but T depends on Base<T>! 
}; 
+0

謝謝。我想你在回答中和抽查器說的是一樣的東西,但是細節很少。 – lapk