0

Essentially, I have a structure of VideoGame statistics like the following in my C++ program:

struct Game
{
    string title;
    genre this_genre;
    int this_rank;
    float time;
};

I also have defined the enumerated type genre as this:

enum genre {FPS, MOBA, ROLEPLAY};

I have declared an abstract structure variable called NewGame

Game NewGame

My goal is the have the user define the members of the structure variable NewGame from standard input. I have no problem doing that for the other members of the structure, but I cannot seem to figure out how to get the user to store an enumerator in the enumerated member of the structure.

cout << "Enter the title for your game: ";
getline(cin, NewGame.title);

cout << "Enter the rank of your game: ";
cin >> NewGame.this_rank;

// The genre currently breaks the code:
cout << "Enter the genre of the game: ";
cin >> NewGame.this_genre;

cout << "Enter the time (days) spent playing your game: ";
cin >> NewGame.time;

I tried static casting it as an integer, but then I overloaded the insertion operator.

cin >> static_cast<int>(NewGame.this_genre); // doesn't work. 

I want for the user to be able to provide values 0, 1, or 2, and have those respectively be assigned to FPS (0), MOBA (1), or ROLEPLAY (2).

What am I doing wrong? What am I not understanding?

xyz123
  • 651
  • 4
  • 19

2 Answers2

2

You have to read into a temporary int and then use static_cast<genre> to get the enumeration value.

int value;
cin >> value;
NewGame.this_genre = static_cast<genre>(value);

You can "make your code work" with this:

cin >> reinterpret_cast<int&>(NewGame.this_genre);  // bad

but don't do that, because it's undefined behavior to assign a value through such a type-punned reference.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
Davis Herring
  • 36,443
  • 4
  • 48
  • 76
  • From what I've observed reinterpret_cast is a common means of reading and writing to binary files. What is undefined about your solution, producing surprising results? – xyz123 Oct 24 '17 at 06:45
  • 1
    @xyz123: You can use `reinterpet_cast`, but only with certain special types (including `char*`) to support such use cases. – Davis Herring Oct 24 '17 at 06:50
  • @xyz123 - It's undefined for two reasons: (1) The C++ standard leaves type punning as undefined behavior in general. Compiler writers can use such assumptions to emit really optimal code in terms of performance. (2) As an instance of the above, nobody promises you the value representation of the enum is the same as the value representation of an `int`. You could theoretically end up with `gen` not equal to *any* of the enumerators. – StoryTeller - Unslander Monica Oct 24 '17 at 06:51
  • Oh, that's rather interesting. Something to think about. – xyz123 Oct 24 '17 at 06:52
  • 1
    @xyz123 - Yes, it is. You should also know, that compilers are often quite smart. On a platform where the punning *could* work, the compiler will probably end up reading directly into the enum filed in the emitted code. It will eliminate the intermediate int and `static_cast` (because it knows what a `static_cast` is, and what you want to achieve with it). – StoryTeller - Unslander Monica Oct 24 '17 at 06:54
1

Have the user input an integer, validate it, and then cast. The way you tried fails because you pass an rvalue to the insertion operator. static_cast<int> returns an integer, it doesn't transmogrify NewGame.this_genre into an integer for the type system.

int gen;
cin >> gen;
if(/*gen is valid*/)
  NewGame.this_genre = static_cast<genre>(gen);
StoryTeller - Unslander Monica
  • 165,132
  • 21
  • 377
  • 458