String in Hash umwandeln - zur Kompilierzeit



  • Hallo,

    gibt es irgendeine Möglichkeit, einen String zur Kompilierzeit in einen Hash umzuwandeln, damit ich Switch-Case-Konstrukte abwickeln kann?

    Scheinbar nehmen Templates keine Zeichenkettensymbole ...

    Die entsprechende statische Hash-Methode:

    const int Helper::hash( const string s ) {
       int h = 0;      
       for (unsigned int i=0; i<s.length(); i++)
                h = 31*h + s[i];
       return h;
    }
    

    In den unten stehenden case-Zweigen sollen zur Kompilierzeit die Zeichenkettenkonstanten in die entsprechenden Hash-Werte umgewandelt werden, denn so wie unten funktioniert das nicht, da case konstante Werte benötigt! Bei switch muss die Hash-Funktion jedoch zur Laufzeit aufgerufen werden!

    Ist dies irgendwie mit einem

    template<const char * c> struct hash
    

    oder so möglich?

    void Pkw::setFahrzeugklasse( string fzkl )
    {
    //Die Methode soll nachher erweiterbar sein, sodass in den Case-Zweigen verschiedene Attribute gesetzt werden!
    	switch( Helper::hash(fzkl) )
    	{
    	 case Helper::hash("Kleinwagen"):   ;
    	 case Helper::hash("Mittelklasse"): ;
    	 case Helper::hash("Luxusklasse"):
    	     fahrzeugklasse = fzkl; break;
    	 default: break;
    	}
    }
    

    Ich würde mich über eine Antwort sehr freuen.



  • In C++11 mit constexpr usw.: ja. In C++03: nein 🙂



  • Ich habe es gerade gelesen:

    C++11 removes the restriction that the variables must be of integral or enumeration type if they are defined with the constexpr keyword.

    Welche Version von gcc benötige ich dafür?

    Ich habe im Moment die Version 4.5.2 (benutze Slackware 1.3.37) ...



  • pumuckl schrieb:

    In C++03: nein 🙂

    In C++03: Möglich, aber mühsam (man nehme z.B. Boost.MPL.String dafür). Bei der gegebenen Hash-Methode ist das aber sicher noch machbar.



  • @correct0r: geht das auch ohne die Boost libraries?



  • Boost kocht ja auch nur mit Wasser. richte dich aber darauf ein, dass es mühsam, zeitaufwendig und alles andere als einfach ohne Boost wird.


  • Mod

    Braucht das hier überhaupt einen Hash? Das sieht hier doch nach einem sehr übertriebenen Anwendungsfall aus. Falls es doch unbedingt Hashes sein müssen, dann hat man hier doch aber wenigstens eine überschaubare Menge an Möglichkeiten. Dann kann man sich die Hashes doch auch vorher explizit ausrechnen lassen. Oder zur Not zur Laufzeit eine map aller Möglichkeiten generieren (damit man auch garantiert die richtige Hashfunktion hat), die Zeit dazu sollte klein sein gegenüber der Zeit zum Nachschlagen, wenn man schon der Meinung war, einen Hashlookup zu benötigen.


  • Mod

    Mit modernem C++ relativ einfach (bei g++ gibt es constexpr-Unterstützung ab 4.6)

    #include <cstddef>
    #include <string>
    #include <iostream>
    
    template <std::size_t N>
    constexpr int hash(const char(&s)[N], std::size_t pos = N-2) {
       return pos == 0 ? s[pos] : s[pos] + 31 * hash( s, pos - 1 );
    }
    int hash(std::string s) {
       int h = 0;
       for (unsigned int i=0; i<s.length(); i++)
                h = 31*h + s[i];
       return h;
    }
    
    int main()
    {
        std::string x = "test";
        switch ( hash(x) )
        {
        case hash("a"): std::cout << "a\n"; break;
        case hash("test"): std::cout << "test\n"; break;
        default: std::cout << "default\n";
        }
    }
    

    in C++03 nicht völlig unmöglich aber umständlich.


Anmelden zum Antworten