switch-Ausdruck des Typs 'std::string' nicht zulässig



  • Hallo,
    ich habe mir gedacht, dass ich zur Übung ein kleines Programm schreiben will, dass auf verschiedene Befehle reagiert, die in der Konsole eingegeben werden.
    Das Programm sieht so aus:
    (Die Variablen werden in der Master.h declariert)

    #include "Master.h"
    
    void SwichtOnCommand(std::string Command);
    
    int main(void)
    {
    	while(!Beenden)
    	{
    		//std::cin >> Eingabe;
    		scanf("%s", Eingabe);
    		SwichtOnCommand(Eingabe);
    		Eingabe = NULL;
    	}
    }
    
    void SwichtOnCommand(std::string Command)
    {
    	switch(Command)
    	{
    	case "help":
    		std::cout << "Bitte geben sie einen der folgenden Befehle
                                  an:" << '\n';
    		std::cout << "help  -  Zeigt eine Auflistung verschiedener
                                  Befehle" << '\n';
    		std::cout << "exit  -  Beendet die
                                  Anwendung" << '\n';
    		return;
    	case "exit":
    		Beenden = true;
    		return;
    	}
    
    	std::cout << "Bitte geben sie einen gültigen Befehl
                          ein..." << '\n';
    }
    

    Jetzt ist mein Problem, dass immer der Fehler kommt:

    error C2450: switch-Ausdruck des Typs 'std::string' nicht zulässig
    
    error C2051: case-Ausdruck ist keine Konstante
    
    error C2051: case-Ausdruck ist keine Konstante
    

    Funktioniert das überhaupt nicht, dass man Strings bei switch-Anweisungen benutzt?

    MFG
    Neokil



  • Neokil schrieb:

    Funktioniert das überhaupt nicht, dass man Strings bei switch-Anweisungen benutzt?

    Genau.



  • Die switch-Anweisung erwartet einen skalaren/ordinalen Typ (ganzzahlig) also char, short, int, long usw.

    Ein vergleich von Strings wie es in machen anderen Sprachen möglich ist, ist in C++ nicht erlaubt.



  • du solltest deine strings zB nach int für zahlen oder char für buchstaben konvertieren.
    eine einfache Möglichkeit:

    #include<sstream>
    #include<string>
    using namespace std;
    
    int main()
    {
    string a="123";
    stringstream sstr;L
    int b;
    sstr<<a;
    sstr>>b;//jetzt hat be den wert von a;
    }
    

    mfg,
    andi01.



  • Wie du evtl siehst, hat er keine Zahlen als Befehle...

    Aber wenn man nach C++ string switch map sucht, bekommt man eine Möglichkeit zumindest sowas in der Art hinzubekommen...



  • genau deswegen steht ja oben dass es auch mit buchstaben ganz genauso geht. das geht ganz einfach mit stringstream zu konvertieren(siehe oben!).

    eben einfach int durh char-array ersetzen:

    #include<sstream>
    #include<string>
    using namespace std;
    
    int main()
    {
    string a="abc";
    char b[100];
    stringstream sstr;
    sstr<<a;
    sstr>>b;//jetzt hat b den wert von a
    }
    

    mfg,
    andi01.



  • @andi01
    Ich vermute mal nicht, dass das bei Strings wie "help" funktioniert.

    //edit deine verbesserung mit dem char array ist auch nicht besser. Ein string IST ein char array. Insofern lässt sich deine konvertierung mit string::c_str() wesentlich einfacher vornehmen. Vergleichen kannst dus trotzdem noch nicht in switch 🙄

    @topic je nachdem wie viele solcher Strings du hast, kannst du einfach if-Anweisungen verwenden. Sind es viele Befehle, dann kannst du zum beispiel sowas machen:

    void printHelp()
    {
        cout<<"Dies ist die Hilfe";
    }
    
    //in der Main
    map<string,void (*)()> commands;
    typedef map<string,void (*)()>::iterator Command;
    
    //füllen...
    commands["help"]=printHelp;
    
    string input;
    cin>>input;
    
    Command m=commands.find(input);
    if(m!=commands.end())
    {
        m->second();
    }
    else
    {
        cout<<"ungueltiger Befehl";
    }
    


  • @otze: doch, tut es. hab es selbst getestet, geht hervorragend!!! und ist noch dazu sehr einfach, wenn es erstmal konvertiert ist muss mans ja nicht in strings vergleichen.

    mfg,
    andi01.



  • dann schau mal meinen Edit. (und den zeitpunkt deines letzten Edits und meines Posts.)



  • jo, hab ich auch grade gesehen. Um das ganze ein wenig abzukürzen: beide methoden sind voll funktionstüchtig und klappen einwandfrei, welche er wählen will muss er selber wissen.

    jedenfalls muss er es (egal mit welcher der beiden methoden) konvertieren bevor er es vergleichen kann.

    mfg,
    andi01.



  • Was sind "beide Methoden"? Wenn du deine meinst: Nein, tun sie nicht. Beide. Die erste Methode scheitert daran, dass die Strings keine Zahlen darstellen, die andere ist definitiv nicht in der Lage, das Problem zu lösen - wie auch, dein Code verändert nichts. Zumal du auf das Hauptproblem, den Switch selbst, nicht eingegangen bist.



  • man kann das ganze auch anschließend einfach mit if-bedingungen lösen, dann könnte man meine methode durchaus anwenden, muss ja nicht unbedingt ein switch sein. wenn man einen switch verwenden will kann man die kommandos theoretisch sogar in zahlen umwandeln (help=1; switch(command) ...), das würde aber nur unnötig aufwand bedeuten.

    mit beide methoden meine ich:
    1. er kann es direkt mit if-bedingungen lösen(z.B. if command=="help")("deine" methode).
    2. er kann es(wenn es denn unbedingt ein switch sein muss) auch erst nach int konvertieren (zB durch ersetzen: help=1, exit=2,...) und dann seinen switch verwenden ("meine" methode).

    beides funktioniert.

    mfg,
    andi01.



  • andi01 schrieb:

    mit beide methoden meine ich:
    1. er kann es direkt mit if-bedingungen lösen(z.B. if command=="help")("deine" methode).
    2. er kann es(wenn es denn unbedingt ein switch sein muss) auch erst nach int konvertieren (zB durch ersetzen: help=1, exit=2,...) und dann seinen switch verwenden ("meine" methode).

    zu 1. Nein, das war nur ein "könnte man machen, wenn sich etwas richtiges nicht lohnt". Meine Lösung kam danach(Der Codeblock)
    zu 2. Wenn das deine Methode sein sollte, dann solltest du noch einmal in dich gehen, und das Problem betrachten, dann deine Lösung durchschauen und überlegen, was dein Code an dem Problem überhaupt ändert.

    Die Antwort darauf ist: herzlich wenig. Das geht mit nem Stringstream nämlich gar nicht. dafür brauchst du eine Lookup-table. Siehe meine map Lösung. Ersetze den Funktionszeiger durch int, dann hast du das, was du eventuell erreichen wolltest.



  • meine lösung würde ungefähr so aussehen:

    string command;
    cin>>command;
    stringstream sstr;
    int command_neu;
    sstr<<command;
    sstr>>command_neu;
    if(command=="help")
    {
    command_neu=1;
    }
    if(command=="exit")
    {
    command_neu=2;
    }
    switch(command_neu)
    {
    case 1:
    cout<<" Hilfe ausgeben"\n";
    break;
    case 2:
    //progamm beenden
    break;
    }
    }
    

    aber die würde ich nur nehmen wenn es unbedingt ein switch sein muss, ansonsten gleich if-bedingungen.

    mfg,
    andi01.



  • andi01 schrieb:

    string command;
    cin>>command;
    
    //Welchen Nutzen hat das hier für das Programm?
    stringstream sstr;
    int command_neu;
    sstr<<command;
    sstr>>command_neu;
    
    //Wenn du hier die if-kaskaden machst, dann brauchst du den Switch 
    //dahinter nicht mehr.
    if(command=="help")
    {
    //dann könnte hier schon die Hilfe stehen
    command_neu=1;
    }
    if(command=="exit")
    {
    //und hier wird das Programm beendet
    command_neu=2;
    }
    
    //und das wird unnötig
    switch(command_neu)
    {
    case 1:
    cout<<" Hilfe ausgeben"\n";
    break;
    case 2:
    //progamm beenden
    break;
    }
    }
    


  • Wenn ich den Befehl unbedingt in eine Ganzzahl für ein switch umwandeln wollen würde, dann würde ich ein Array (vector, was auch immer) von Befehlen erstellen, den String in diesem Array suchen und den Index des gefundenen Elements als Nummer nehmen.

    Damit wäre ich aber nicht im mindesten zufrieden, weil die Nummer zu einer Magic Number verkommt, denn man hat keine offensichtliche Zuordnung zwischen Nummer und Befehl. Um das, was daraus folgt abzukürzen, letztlich würde es (bei mir) auf eine Map Befehl auf Funktor hinauslaufen, womit switch wieder hinfällig wäre.



  • LordJaxom schrieb:

    Damit wäre ich aber nicht im mindesten zufrieden, weil die Nummer zu einer Magic Number verkommt, denn man hat keine offensichtliche Zuordnung zwischen Nummer und Befehl.

    if(...)
    m["Help"]=CMD_HELP;
    m["Exit"]=CMD_EXIT;
    m["Menu"]=CMD_MENU;
    else
    m["Hilfe"]=CMD_HELP;
    m["Raus"]=CMD_EXIT;
    m["Menü"]=CMD_MENU;
    


  • volkard schrieb:

    if(...)
    m["Help"]=CMD_HELP;
    m["Exit"]=CMD_EXIT;
    m["Menu"]=CMD_MENU;
    else
    m["Hilfe"]=CMD_HELP;
    m["Raus"]=CMD_EXIT;
    m["Menü"]=CMD_MENU;
    

    Letztlich geht es bei Design ja darum, Wartbarkeit zu erhöhen und Arbeit zu verringern.
    Hier müsste man für weitere Befehle an mindestens drei Stellen ansetzen, bei den Konstanten, beim Füllen der Map und bei der Auswertung im Switch. Da sowieso schon eine Map vorliegt, würde ein Speichern von Funktionszeigern (statt IDs) einen dieser Schritte eliminieren, da man nur noch beim Füllen der Map eine Funktion ergänzen muss. Zudem würde ein Schritt "abgesichert", da ein Vergessen der Definition dieser Funktion zu einem Compile- oder Linkerfehler führt, statt im switch einfach nur in den default-Zweig zu laufen (Laufzeitfehler oder garkein Fehler).

    (Das war der Schritt, den ich im letzten Post abgekürzt habe)

    Das aber nur der Vollständigkeit halber.



  • also ich habe die Funktion "SwitchOnCommand" jetzt so abgeändert:

    void SwichtOnCommand(std::string Command)
    { 
    	std::stringstream str_Command;
    	char c_Command[250];
    
    	str_Command << Command;
    	str_Command >> c_Command;
    
    	switch(c_Command)
    	{
    	case "help":
    		std::cout << "Bitte geben sie einen der folgenden Befehle
                                  an:" << '\n';
    		std::cout << "help  -  Zeigt eine Auflistung verschiedener
                                  Befehle" << '\n';
    		std::cout << "exit  -  Beendet die
                                  Anwendung" << '\n';
    		return;
    	case "exit":
    		Beenden = true;
    		return;
    	}
    
    	std::cout << "Bitte geben sie einen gültigen Befehl
                          ein..." << '\n';
    }
    

    allerdings will Switch bei mir nicht mal char-Arrys benutzen:

    error C2450: switch-Ausdruck des Typs 'char[250]' nicht zulässig
    

    Hab ich was falsch initialisiert oder funktioniert das auch nicht?

    MFG
    Neokil



  • DeepCopy schrieb:

    Die switch-Anweisung erwartet einen skalaren/ordinalen Typ (ganzzahlig) also char, short, int, long usw.



  • 👎
    Da merkt man mal,
    a) wie ein einzelner "engagierter Halbwissenverbreiter" mehr bewirkt kann als ein ganzer Haufen von Experten wieder reparieren kann und
    b) dass nicht wenige Fragende den Thead (erstmal? nur?) nach abtippbarem Quellcode scannen. Erklärungen ist Schall und Rauch... (oder zu schlecht/anspruchsvoll formuliert)

    Mein Vorschlag an andi01: Lösche Deine Beiträge hier im Thread, bevor noch mehr Ahnungslose in diese Falle tappen. Dein Tipp zur Konvertierung nach char[] hat gar nichts mit dem Problem zu tun (die if/else-Kaskade hätte hilfreich sein können, wenn Du sie nicht mit dem char[]-Zeug vermischt hättest).

    Gruß,

    Simon2.


Anmelden zum Antworten