Evaluate a string with a switch in C++

C++

C++ Problem Overview


I want to evaluate a string with a switch but when I read the string entered by the user throws me the following error.

#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

C++ Solutions


Solution 1 - C++

As said before, switch can be used only with integer values. So, you just need to convert your "case" values to integer. You can achieve it by using constexpr from c++11, thus some calls of constexpr functions can be calculated in compile time.

something like that...

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

where str2int is like (implementation from here):

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

Another example, the next function can be calculated in compile time:

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 

Solution 2 - C++

You can map the strings to enum values, then switch on the 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;
    }
}

Resolving the enum can be implemented as a series of if checks:

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

Or a map lookup:

 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->second;
    }
    return Option_Invalid; 
}

Solution 3 - C++

A switch statement can only be used for integral values, not for values of user-defined type. (And even if it could, your input operation doesn't work, either. The >> operation extracts single tokens, separated by whitespace, so it can never retrieve a value "Option 1".)

You might want this:

#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.

Solution 4 - C++

You can only use switch-case on types castable to an int.

You could, however, define a std::map<std::string, std::function> dispatcher and use it like dispatcher[str]() to achieve same effect.

Solution 5 - C++

You can't. Full stop.

switch is only for integral types, if you want to branch depending on a string you need to use if/else.

Solution 6 - C++

what about just have the option number:

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

Solution 7 - C++

Switch value must have an Integral type. Also, since you know that differenciating character is in position 7, you could switch on a.at(7). But you are not sure the user entered 8 characters. He may as well have done some typing mistake. So you are to surround your switch statement within a Try Catch. Something with this flavour

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

The default clause in switch statement captures cases when users input is at least 8 characters, but not in {1,2,3}.

Alternatively, you can switch on values in an enum.

EDIT

Fetching 7th character with operator[]() does not perform bounds check, so that behavior would be undefined. we use at() from std::string, which is bounds-checked, as explained here.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionAlejandro CaroView Question on Stackoverflow
Solution 1 - C++SerhiyView Answer on Stackoverflow
Solution 2 - C++mskfisherView Answer on Stackoverflow
Solution 3 - C++Kerrek SBView Answer on Stackoverflow
Solution 4 - C++rmnView Answer on Stackoverflow
Solution 5 - C++syamView Answer on Stackoverflow
Solution 6 - C++gongzhitaaoView Answer on Stackoverflow
Solution 7 - C++kiriloffView Answer on Stackoverflow