2016-11-09 20 views
0

混亂,我發現這段代碼在其他話題編譯時間哈希 - 模板演繹順序

template<size_t N, size_t I = 0> 
struct hash_calc 
{ 
    static constexpr size_t apply(const char(&s)[N]) 
    { 
    return (hash_calc < N, I + 1 >::apply(s)^s[I]) * 16777619u; 
    }; 
}; 

template<size_t N> 
struct hash_calc<N, N> 
{ 
    static constexpr size_t apply(const char(&s)[N]) 
    { 
    return 2166136261u; 
    }; 
}; 

template<size_t N> 
constexpr size_t hash(const char(&s)[N]) 
{ 
    return hash_calc<N>::apply(s); 
} 

首先,我完全糊塗了,爲什麼它不端無限遞歸調用?據我所知,第一個hash_calc<N, I>總是打電話給自己,當I達到N時,是什麼導致它在hash_calc<N, N>處中斷?當N == I時,hash_calc<N, I>的模板實例化不會失敗。 第二 - 我試圖複製粘貼hash_calc<N, N>結構hash_calc<N, I>這會導致編譯錯誤error: 'hash_calc' is not a class template struct hash_calc<N, N>。這是爲什麼?!

編輯: 下面的修改後的代碼不能在msvc和gcc下編譯。我剛剛把一個模板放在其他模板上。發生了什麼?

template<size_t N> 
struct hash_calc<N, N> 
{ 
    static constexpr size_t apply(const char(&s)[N]) 
    { 
     return 2166136261u; 
    }; 
}; 

template<size_t N, size_t I = 0> 
struct hash_calc 
{ 
    static constexpr size_t apply(const char(&s)[N]) 
    { 
    return (hash_calc < N, I + 1 >::apply(s)^s[I]) * 16777619u; 
    }; 
}; 

template<size_t N> 
constexpr size_t hashq(const char(&s)[N]) 
{ 
    return hash_calc<N>::apply(s); 
} 
+0

模板實例化過程將盡可能在主模板上使用部分特化。畢竟,這就是提供專業化的重點 - 這樣,當它們與實際參數相匹配時,它們就可以得到使用。您似乎認爲主模板必須在專業化被考慮之前未能實例化 - 事實並非如此。 –

+0

*「我試着將'hash_calc 'struct複製粘貼到'hash_calc ''*我不明白你的意思。如果你有一段產生編譯器錯誤的代碼,那麼顯示那段代碼和編譯器錯誤的確切文本。 –

+0

我修改了第一篇文章 – QQemka

回答

0

我完全糊塗了,爲什麼它不端無限遞歸調用?

讓我們一步一步來看看它。

hashq<N>(const char(&s)[N])來電hash_calc<N>::apply(s);

這就是:

template<size_t N, size_t I = 0> 
struct hash_calc 
{ 
    static constexpr size_t apply(const char(&s)[N]) 
    { 
    return (hash_calc < N, I + 1 >::apply(s)^s[I]) * 16777619u; 
    }; 
}; 

I==0。 現在hash_calc < N, I + 1 >::apply(s)被調用,與I==1,這一直持續到I==N。那時

template<size_t N> 
struct hash_calc<N, N> 
{ 
    static constexpr size_t apply(const char(&s)[N]) 
    { 
     return 2166136261u; 
    }; 
}; 

被調用。遞歸結束。

爲什麼?

template<size_t N, size_t I = 0> 
struct hash_calc 
{ 
    static constexpr size_t apply(const char(&s)[N]) 
    { 
    return (hash_calc < N, I + 1 >::apply(s)^s[I]) * 16777619u; 
    }; 
}; 

是更一般的情況下,它處理任何對<N,I>,而

template<size_t N> 
struct hash_calc<N, N> 
{ 
    static constexpr size_t apply(const char(&s)[N]) 
    { 
     return 2166136261u; 
    }; 
}; 

是其專業化,它只能處理的<N,N>的情況。 編譯器首先需要一般情況,然後是專業化。

+0

哦,我沒有注意到第一眼看到專業化...我習慣於'template <>'語法,'template '確實是一個專業化,但看起來不像'<>' ,那是多麼困惑我。 非常感謝! – QQemka