2015-01-14 28 views
0

爲什麼在將#if 0更改爲#if 1時出現「錯誤C1202:遞歸類型或函數依賴關係上下文過於複雜」錯誤?錯誤版本更簡單,我寧願使用類似的東西。C++ 11遞歸類模板到複雜錯誤

我想寫一個散列函數,消除編譯時間常量長度的循環。真正的哈希函數更復雜,這只是一個簡單的例子。

typedef unsigned __int8 U1; 
typedef unsigned __int16 U2; 
typedef unsigned __int32 U4; 
#define AS1(a_)  (*(U1*)(a_)) 
#define AS2(a_)  (*(U2*)(a_)) 
#define AS3(a_)  ((U4(((U1*)(a_))[2])<<16) | AS2(a_)) 
#define AS4(a_)  (*(U4*)(a_)) 

#if 0 
template<U4 CB> U4 Hash(const char* sz, int n = 0) { 
    if (CB >= 4) return Hash<CB - 4>(sz + 4, n^AS4(sz)); 
    if (CB == 3) return n^AS3(sz); 
    if (CB == 2) return n^AS2(sz); 
    if (CB == 1) return n^AS1(sz); 
} 
#else 
template<U4 CB> U4 Hash(const char* sz) { 
    return Hash<CB - 4>(sz + 4, Hash<4>(sz)); 
} 
template<U4 CB> U4 Hash(const char* sz, int n) { 
    return Hash<CB - 4>(sz + 4, Hash<4>(sz, n)); 
} 
template<> U4 Hash<1>(const char* sz, int n)  { return n^AS1(sz); } 
template<> U4 Hash<2>(const char* sz, int n)  { return n^AS2(sz); } 
template<> U4 Hash<3>(const char* sz, int n)  { return n^AS3(sz); } 
template<> U4 Hash<4>(const char* sz, int n)  { return n^AS4(sz); } 
template<> U4 Hash<1>(const char* sz)   { return AS1(sz); } 
template<> U4 Hash<2>(const char* sz)   { return AS2(sz); } 
template<> U4 Hash<3>(const char* sz)   { return AS3(sz); } 
template<> U4 Hash<4>(const char* sz)   { return AS4(sz); } 
#endif 

int main(int argc, char* argv[]) 
{ 
    char* sz = "123456789"; 
    int n = Hash<9>(sz); 
    n += Hash<3>(sz); 
    return n; 
} 

回答

3

問題是這樣的功能是無限遞歸在編譯時:

template<U4 CB> U4 Hash(const char* sz, int n = 0) { 
    if (CB >= 4) return Hash<CB - 4>(sz + 4, n^AS4(sz)); 
    if (CB == 3) return n^AS3(sz); 
    if (CB == 2) return n^AS2(sz); 
    if (CB == 1) return n^AS1(sz); 
} 

當然,你有if報表,因此,如果您撥打Hash<3>你並不真的指望它要實例Hash<-1> ...但在模板中,函數的整個主體必須​​被實例化。分支只在稍後修剪。所以不管CB價值的Hash任何實例將保持實例的CB越來越多值(例如Hash<9>需要Hash<5>需要Hash<1>需要Hash<-3>需要Hash<-7> ...),直至碰到編譯模板遞歸限制或編譯器只是用完內存

在另一方面,如果你明確地專注所有的案件:

template<U4 CB> U4 Hash(const char* sz, int n = 0) { 
    return Hash<CB - 4>(sz + 4, n^AS4(sz)); 
} 

template <> U4 Hash<3>(const char* sz, int n = 0) { 
    return n^AS3(sz); 
} 

// etc. 

然後,比方說,Hash<9>實例化會導致Hash<5>的實例,然後Hash<1>只是一個明確的專業化,並且過程停在那裏。

這就是爲什麼當涉及到模板元編程時,您應該將專業化看作您的分支和基礎遞歸情況。不要想到實際的運行時早午餐。

+0

Bam!謝啦。大師解釋它時很簡單。 – johnnycrash

+0

有什麼辦法來簡化它,所以我不需要一個需要n和一個不是? – johnnycrash

+0

@johnnycrash你可以重寫,以便'哈希(sz)'只是'返回AS4(sz)^哈希(sz + 4);'但它可能是更好的保持尾遞歸,你會有檢查你的編譯器對它做了什麼。 – Barry