2016-11-09 2 views
0

Ich habe dieses Stück Code in anderem ThemaCompile Zeit Hash - Verwirrung auf Vorlage Abzug um

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); 
} 

Zunächst einmal, ich bin gefunden total verwirrt, warum es nicht ein unendlicher rekursiven Aufruf zu sein endet? Von dem, was ich verstehe, zuerst hash_calc<N, I> wird sich immer selbst anrufen, was bewirkt, dass es bei hash_calc<N, N> zu brechen, wenn IN erreicht? Die Vorlageninstanziierung für hash_calc<N, I> schlägt nicht fehl, wenn N == I. Zweitens - ich habe versucht, kopieren Sie die hash_calc<N, N> Struktur über hash_calc<N, I>, die Kompilierungsfehler error: 'hash_calc' is not a class template struct hash_calc<N, N> verursacht. Warum das?!

Edit: Der modifizierte Code unten kompiliert nicht unter msvc noch gcc. Ich habe gerade eine Vorlage über andere gelegt. Was ist passiert?

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

Der Template-Instanziierungsprozess verwendet wann immer möglich eine partielle Spezialisierung über die primäre Vorlage. Das ist schließlich der springende Punkt, Spezialisierungen bereitzustellen - damit sie verwendet werden, wenn sie mit den tatsächlichen Argumenten übereinstimmen. Sie scheinen zu glauben, dass die primäre Vorlage nicht instanziiert werden kann, bevor die Spezialisierung berücksichtigt wird - das ist nicht der Fall. –

+0

* "Ich habe versucht, die' hash_calc 'struct über' hash_calc '* Ich habe nicht verstanden, was Sie damit meinen. Wenn Sie einen Code haben, der einen Compilerfehler verursacht, zeigen Sie diesen Code und den genauen Text des Compilerfehlers an. –

+0

Ich habe den ersten Beitrag geändert – QQemka

Antwort

0

Ich bin total verwirrt, warum es nicht ein unendlicher rekursiven Aufruf zu sein endet?

Also schauen wir uns Schritt für Schritt an.

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

Das ist:

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; 
    }; 
}; 

mit I==0. Nun wird hash_calc < N, I + 1 >::apply(s) aufgerufen, mit I==1 geht das weiter bis I==N. Das ist, wenn

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

heißt. Und die Rekursion endet.

Warum ist das ?!

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; 
    }; 
}; 

ist der allgemeinere Fall ist es jedes Paar von <N,I> Griffe, während

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

ihre Spezialisierung ist, nur den Fall von <N,N> verarbeiten kann. Der Compiler benötigt zuerst den allgemeinen Fall und dann die Spezialisierung.

+0

Oh, ich habe die Spezialisierung auf den ersten Blick nicht bemerkt ... Ich bin an die 'template <>' Syntax gewöhnt, die 'template ' ist eine Spezialisierung, sieht aber nicht wie '<>' aus Das verwirrt mich. Vielen Dank! – QQemka