[gelöst] switch bei wxString



  • Hallo,

    ich schreibe gerade für mein Musikerprogramm einen Parser, der mir anhand einer Text-Datei den Schlagzeugrythmus aufzeigt.
    Beispiel der Datei:

    // Schlag 1 | RechterFuss | Basedrum
    1|RF|B
    3|RF|B
    3+|RF|B
    // Schlag 2 | LinkeHand | Snare
    2|LH|S
    2+|LH|S
    4|LH|S
    // Schlag 1 | RechteHand | COWbell
    1|RH|COW
    2|RH|COW
    3|RH|COW
    4|RH|COW
    

    dazu habe ich eine Funktion, die mir Zeilenweise die Datei ausliest. Jetzt gibt es beim Schlagzeug natürlich viele Elemente die es zu bedienen gibt. Basedrum, Snare, HiHatt, Tom1, Tom2, Tom3, Tom4, Kuhglocke, etc...

    enum mB2MuDrSchlagzeugerElemente {
    	LF, RF, RH, LH
    };
    
    enum MidiGMDrums {
    	gmDrumBassDrum2 = 35, gmDrumBassDrum1, gmDrumSideStick,
    	gmDrumSnareDrum1, gmDrumHandClap, gmDrumSnareDrum2 //...
    };
    
    bool auslesen(line, MidiGMDrums& note, mB2MuDrSchlagzeugerElemente& element)
    {
    //...
      // LF, RF, RH, LH ???
      wxString wls = line.Mid(vorne+1,hinten);
      if (wls.IsSameAs(_T("RH")))	{ element = RH;	}
      else if (wls.IsSameAs(_T("LH"))) { element = LH; }
      else if (wls.IsSameAs(_T("RF"))) { element = RF; }
      else if (wls.IsSameAs(_T("LF"))) { element = LF; }
      else return false;
      // Element
      wxString nod = line.Mid(vorne+hinten+2);
      if (nod.IsSameAs(_T("B"))) { note = gmDrumBassDrum1; }
      else if (nod.IsSameAs(_T("S"))) { note = gmDrumSnareDrum1; }
      else if (nod.IsSameAs(_T("H"))) { note = gmDrumClosedHiHat; }
      // ....
      else return false;
    //...
    }
    

    Damit geht das schon mal, allerdings ist die Liste bei mir sehr lange, weil (wie oben schon erwähnt) ich derzeit wg. GeneralMidi schon alleine 81 Schlgazeugelemente habe. Eine Switch-Anweisung wäre supi.

    bool auslesen(line)
    {
    //...
      // Element
      wxString nod = line.Mid(vorne+hinten+2);
      switch (nod)
      {
        case _T("B"): note = gmDrumBassDrum1; break;
        // ....
        default: return false;
      }
    //...
    }
    

    Leider bekomme ich immer die Aussage:

    1>musiker_schlagzeuger.cpp
    1>musiker_schlagzeuger.cpp(181) : error C2450: switch-Ausdruck des Typs 'wxString' nicht zulässig
    1>        Kein benutzerdefinierter Konvertierungsoperator verfügbar, der diese Konvertierung durchführen kann, oder der Operator kann nicht aufgerufen werden
    1>musiker_schlagzeuger.cpp(183) : error C2051: case-Ausdruck ist keine Konstante
    1>musiker_schlagzeuger.cpp(185) : warning C4065: switch-Anweisung enthält 'default', aber keine case-Marken
    

    Was tun, was nun?
    Bitte um Hilfe, weil ich mal vermute, dass eine switch-Anweisung wahrscheinlich auch schneller wäre als eine "if else if else if else if else if else"-Anweisung.

    Danke,
    Stefan



  • Beim switch darfst du nur Integer-Typen verwenden (int, char...). Du musst also bei if - else if bleiben.

    Und schneller wäre ein switch sicher nicht...



  • Gibts denn einen anderen Grundgedanken für solche Parser?



  • WX_DECLARE_STRING_HASH_MAP( int, elementeMap);
    WX_DECLARE_STRING_HASH_MAP( int, drumsMap);

    //Maps füllen
    elementeMap["LH"] = LH;
    elementeMap["RH"] = RH;
    ...
    drumsMap["B"] = gmDrumBassDrum1;
    drumsMap["S"] = gmDrumSnareDrum1;
    ...

    //Auswertung
    elementeMap::iterator it;

    it = elementeMap.find(string);
    if (it == hashmap.end())
    ->Meldung das string nicht in map definiert
    int element = it->second; //element erhält value aus map


  • Mod

    Also es geht sehr wohl anders.

    Für Strings gibts keine switches, und ich denke generell sollte man das switch statement meiden.

    Du könntest einen eigenen Parser dafür schreiben, z.b. mit boost::spirit. das würde funktionieren.
    Oder du könntest eine map mit funktionszeigern anlegen: ala std::map<wxString,Functor/Funktionszeiger>.

    Der einfachheit halber nehme ich da jetzt mal boost::function:

    //pseudocode
    std::map<wxString, boost::function<void()> > strmap;
    strmap.insert(std::make_pair("BF",boost::bind(&SchlagzeugKlasse::OnBF,Zeigeraufschlagzeugklasse)));
    ... für den rest genauso.
    
    strmap["BF"]();//ruft die Methode/Funktion für "BF" auf.
    

    Du kannst statt Funktionszeigern natürlich auch normale werte in der Map speichern, je nach dem, was du da als ergebnis brauchst.

    phlox



  • Wäre es nicht sinnvoller, das alles direkt numerisch zu speichern? Also statt LF und RF nimmst du beispielsweise 0 und 1. Sowas kannst du auch beim Einlesen direkt zuweisen. Es sei denn, die Datei soll lesbar (und somit leicht editierbar) bleiben...



  • Danke schon mal,

    jede Menge Infos und jede Menge zu testen. Ich versuch mal mein Glück.
    Die Idee von Softwaremaker scheint mir jetzt fürs erste die schnellste Lösung zu sein. Aber ich werde den Ansatz von phlox81 auch mal ausprobieren.

    @_matze: Da diese Text-Dateien nur im Nodepad (oder vrgl. Editor) bearbeitet werden ist es wohl der einzige Weg für meine Schüler, das es lesabar bleibt.

    Gruß,
    Stefan



  • Ich habe mich nun für den Weg von Softwaremaker entschieden, da es am Einfachsten ist, neue Befehle und Objekte hinzuzufügen und einen Überblick zu behalten.
    Danke.


  • Mod

    stefanjann schrieb:

    Ich habe mich nun für den Weg von Softwaremaker entschieden, da es am Einfachsten ist, neue Befehle und Objekte hinzuzufügen und einen Überblick zu behalten.
    Danke.

    Würde dir aber aufjedenfall von den wxContainern abraten, nimm lieber std::map oder std::hashmap.


Anmelden zum Antworten