2013-05-05 12 views
32

Voglio valutare una stringa con un interruttore ma quando leggo la stringa immessa dall'utente, mi viene il seguente errore.Valutare una stringa con uno switch in C++

#include<iostream> 
using namespace std; 

    int main() { 
     string a; 
     cin>>a; 
     switch (string(a)) { 
     case "Option 1": 
      cout<<"It pressed number 1"<<endl; 
      break; 
     case "Option 2": 
      cout<<"It pressed number 2"<<endl; 
      break; 
     case "Option 3": 
      cout<<"It pressed number 3"<<endl; 
      break; 
     default: 
      cout<<"She put no choice"<<endl; 
      break; 
     } 
     return 0; 
    } 

error: invalid cast from type 'std::string {aka std::basic_string}' to type 'int

+2

'std :: string' non funziona bene con lo switch. – 0x499602D2

+0

Le espressioni di commutazione devono essere valutate su un tipo integrale. – juanchopanza

+0

Gli switch C++ funzionano solo sui tipi interi. Devi codificare nella lingua che stai utilizzando. Il desiderio di una funzione non lo renderà tale. Puoi costruire una mappa da stringhe a numeri interi e quindi passare a quei numeri interi. Oppure la mappa può essere da stringhe a puntatori di funzione, dove una chiamata sul puntatore fa quello che vuoi. – Gene

risposta

12

Un switch istruzione può essere utilizzata solo per valori interi, non per valori di tipo definito dall'utente. E anche se potesse, anche l'operazione di input non funziona.

Si potrebbe desiderare questo:

#include <string> 
#include <iostream> 


std::string input; 

if (!std::getline(std::cin, input)) { /* error, abort! */ } 

if (input == "Option 1") 
{ 
    // ... 
} 
else if (input == "Option 2") 
{ 
    // ... 
} 

// etc. 
+0

Che cosa intendi per "l'operazione di input non funziona"? – UnKnown

+2

@UnKnown: L'operazione '>>' estrae singoli token, separati da spazi bianchi, in modo che non possa mai recuperare un valore '" Opzione 1 "'. –

1

Non è possibile. Punto.

switch è solo per i tipi interi, se si desidera diramare in base a una stringa è necessario utilizzare if/else.

3

che dire basta avere il numero di opzione:

#include <iostream> 
#include <string> 
using namespace std; 

int main() 
{ 
    string s; 
    int op; 

    cin >> s >> op; 
    switch (op) { 
    case 1: break; 
    case 2: break; 
    default: 
    } 

    return 0; 
} 
6

è possibile mappare le corde per enum valori, quindi si accende l'enum:

enum Options { 
    Option_Invalid, 
    Option1, 
    Option2, 
    //others... 
}; 

Options resolveOption(string input); 

// ...later... 

switch(resolveOption(input)) 
{ 
    case Option1: { 
     //... 
     break; 
    } 
    case Option2: { 
     //... 
     break; 
    } 
    // handles Option_Invalid and any other missing/unmapped cases 
    default: { 
     //... 
     break; 
    } 
} 

Risoluzione enum può essere implementato come una serie di if controlli:

Options resolveOption(std::string input) { 
    if(input == "option1") return Option1; 
    if(input == "option2") return Option2; 
    //... 
    return Option_Invalid; 
} 

o di una mappa di ricerca:

Options resolveOption(std::string input) { 
    static const std::map<std::string, Option> optionStrings { 
     { "option1", Option1 }, 
     { "option2", Option2 }, 
     //... 
    }; 

    auto itr = optionStrings.find(input); 
    if(itr != optionStrings.end()) { 
     return *itr; 
    } 
    return Option_Invalid; 
} 
+0

Risoluzione è un'altra funzione o è qualcosa nella libreria standard? –

+0

resolveOption è la funzione personalizzata che calcola il valore dell'enumeratore Opzioni basate sull'input del programma corrente, – LastBlow

+0

Per maggiore chiarezza, ho aggiunto due possibili implementazioni di una funzione 'resolveOption()'. – mskfisher

-1

Il valore dell'interruttore deve essere di tipo Integrale. Inoltre, poiché si sa che il carattere differente è in posizione 7, è possibile attivare a.at(7). Ma non sei sicuro che l'utente abbia inserito 8 caratteri. Potrebbe anche aver commesso un errore di battitura. Quindi devi circondare la tua istruzione switch all'interno di Try Catch. Qualcosa con questo sapore

#include<iostream> 
using namespace std; 
int main() { 
    string a; 
    cin>>a; 

    try 
    { 
    switch (a.at(7)) { 
    case '1': 
     cout<<"It pressed number 1"<<endl; 
     break; 
    case '2': 
     cout<<"It pressed number 2"<<endl; 
     break; 
    case '3': 
     cout<<"It pressed number 3"<<endl; 
     break; 
    default: 
     cout<<"She put no choice"<<endl; 
     break; 
    } 
    catch(...) 
    { 

    } 
    } 
    return 0; 
} 

La clausola di default in un'istruzione switch cattura casi in cui gli utenti di ingresso è di almeno 8 caratteri, ma non in {1,2,3}.

In alternativa, è possibile attivare i valori in un enum.

EDIT

Recupero 7 ° personaggio con operator[]() non esegue controllare limiti, in modo che il comportamento sarebbe stato indefinito. usiamo at() da std::string, che è controllato, as explained here.

+0

@syam grazie, ho modificato – octoback

60

Come detto prima, lo switch può essere utilizzato solo con valori interi. Quindi, è sufficiente convertire i valori "case" in numeri interi. È possibile ottenerlo utilizzando constexpr da C++ 11, quindi alcune chiamate delle funzioni di constexpr possono essere calcolate in fase di compilazione.

qualcosa del genere ...

switch (str2int(s)) 
{ 
    case str2int("Value1"): 
    break; 
    case str2int("Value2"): 
    break; 
} 

dove str2int è come (attuazione da here):

constexpr unsigned int str2int(const char* str, int h = 0) 
{ 
    return !str[h] ? 5381 : (str2int(str, h+1) * 33)^str[h]; 
} 

Un altro esempio, la funzione successiva può essere calcolato in fase di compilazione:

constexpr int factorial(int n) 
{ 
    return n <= 1 ? 1 : (n * factorial(n-1)); 
} 

int f5{factorial(5)}; 
// Compiler will run factorial(5) 
// and f5 will be initialized by this value. 
// so programm instead of wasting time for running function, 
// just will put the precalculated constant to f5 
+2

Il compilatore potrebbe farlo, o potrebbe non farlo. Se hai fatto 'f5'' constexpr', dovrebbe farlo. – Deduplicator

+6

Questo è esattamente il motivo per cui odio lavorare con C++. Viola il principio della minima sorpresa in tanti modi. Questo è uno di loro. – Richard

+0

Eccellente! Molto utile – Fred

10

È possibile utilizzare solo SWITCH- caso su tipi impostabili a un int.

È tuttavia possibile definire uno std::map<std::string, std::function> dispatcher e utilizzarlo come dispatcher[str]() per ottenere lo stesso effetto.

+0

Devi assicurarti che esista una funzione nella mappa, altrimenti [una 'std :: function' costruita in modo predefinito getterà' bad_function_call'] (http://stackoverflow.com/a/7527115/44390). È possibile convalidare la funzione è inizializzata con un semplice controllo bool, come 'auto & fn = dispatcher [str]; if (fn) {fn(); } ' – mskfisher

Problemi correlati