tags:

views:

255

answers:

5

I would like to use an enum value for my switch statment in C++. Is it possible to use the enum values enclosed in the "{}" as choices for the "switch()"? I know that switch() needs an integer value in order to direct the flow of programming to the appropriate case number. If this is the case, do I just make a variable for each constant in the 'enum' statment? I also want the user to be able to pick the choice and pass that choice to the switch() statement.

For example:

cout << "1 - Easy, ";
cout << "2 - Medium, ";
cout << "3 - Hard: ";

enum myChoice { EASY = 1, MEDIUM = 2, HARD = 3 };

cin >> ????

switch(????)
{
case 1/EASY:  // (can I just type case EASY?)
    cout << "You picked easy!";
    break;

case 2/MEDIUM: 
    cout << "You picked medium!";
    break;

case 3/HARD: // ..... (same thing as case 2 except on hard.)

default:
    return 0;
}
A: 

The user's input will always be given to you in the form of a string of characters... if you want to convert the user's input from a string to an integer, you'll need to supply the code to do that. If the user types in a number (e.g. "1"), you can pass the string to atoi() to get the integer corresponding to the string. If the user types in an english string (e.g. "EASY") then you'll need to check for that string (e.g. with strcmp()) and assign the appropriate integer value to your variable based on which check matches. Once you have an integer value that was derived from the user's input string, you can pass it into the switch() statement as usual.

Jeremy Friesner
The code to convert the input from a string to an integer is `int i; cin >> i;`. This isn't C, so there's no need to mess around with the C library.
Mike Seymour
+3  A: 

You can use an enumerated value just like an integer:

myChoice c;

...

switch( c ) {
case EASY:
    DoStuff();
    break;
case MEDIUM:
    ...
}
Peter Ruderman
+2  A: 

You can use a map to map the input to your enum:

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

enum level {easy, medium, hard};
map<string, level> levels;

void register_levels()
{
    levels["easy"]   = easy;
    levels["medium"] = medium;
    levels["hard"]   = hard;
}

int main()
{
    register_levels();
    string input;
    cin >> input;
    switch( levels[input] )
    {
    case easy:
        cout << "easy!"; break;
    case medium:
        cout << "medium!"; break;
    case hard:
        cout << "hard!"; break;
    }
}
AraK
This will return `easy` if the string does not match any of the valid choices.
dreamlax
+4  A: 

You're on the right track. You may read the user input into an integer and switch on that:

  enum Choice
  {
    EASY = 1, 
    MEDIUM = 2, 
    HARD = 3
  };

  int i = -1;

// ...<present the user with a menu>...

  cin >> i;

  switch(i)
  {
  case EASY:
    cout << "Easy\n";
    break;
  case MEDIUM:
    cout << "Medium\n";
    break;
  case HARD:
    cout << "Hard\n";
    break;
  default:
    cout << "Invalid Selection\n";
    break;
  }
Adam
Should probably initialise i to a value that will hit the `default` case, though, or a value interpreted as I/O error.
Steve Jessop
`typedef enum e { ... };` ?? The typedef is optional in C++ but if present, there should be a typedef-ed name after the closing brace. Also, in C++ (as compared to C) you should use the enum type and not `int` for the variable (even if the compiler will gladly take `int`).
David Rodríguez - dribeas
@Steve: agreed. Updated.
Adam
@David: typedef error was definitely not standard form. Fixed.I chose not to declare the input as 'Choice' because that makes the input stream operator '>>' ambiguous.
Adam
Ok on the type of the variable, but still is more C++ like to have: `enum Choice { EASY = 1, MEDIUM = 2, HARD = 3 };` rather than having a typedef of an unnamed enum.
David Rodríguez - dribeas
I guess that's something I picked up from an old mentor and never had a reason to change. Updated in the answer.
Adam
+3  A: 

Some things to note:

You should always declare your enum inside a namespace as enums are not proper namespaces and you will be tempted to use them like one.

Always have a break at the end of each switch clause execution will continue downwards to the end otherwise.

Always include the default: case in your switch.

Use variables of enum type to hold enum values for clarity.

see here for a discussion of the correct use of enums in C++.

This is what you want to do.

namespace choices
{
    enum myChoice 
    { EASY = 1 ,
        MEDIUM = 2, 
        HARD = 3  
    };
}

int main(int c, char** argv)
{
    choices::myChoice enumVar;
    cin >> enumVar;
    switch (enumVar)
    {
        case choices::EASY:
        {
            // do stuff
            break;
        }
        case choices::MEDIUM:
        {
            // do stuff
            break;
        }

        default:
        {
            // is likely to be an error
        }
    };

}
radman
In order for this to work you would need to overload the istream `operator>>` for the enumeration.
James McNellis
+1 overall, but I disagree in the `always provide a default:` case. I understand that the intention is triggering a known error so that it can be easily corrected if a new enumerated value is later added to the enumeration. I prefer actually processing the input to guarantee the correctness of the user data, and not providing a `default` tag, but rather having the compiler warn about switch statements if there is any value that falls outside of all tested cases. This way you get an even faster error report: the compiler will complain if a value is added to the enumeration.
David Rodríguez - dribeas
Also you probably need to initialise `enumVar`. This code yields undefined behavior if `cin >> enumVar` doesn't write a value, which is typically the case when `operator>>` encounters an error. As James says, though, you'll be overloading the operator for the enum anyway, so you could write it to always assign something even on error.
Steve Jessop
good comments and suggestions, that'll learn me to post a code solution without compiling it first :P
radman