Reputation: 13
I am trying to output a element of enum I declared but for example, when I input push_ups, it outputs a number like 8621623 instead of showing push_ups. I have no idea why. I am Japanese so I am sorry if my English is broken. Thank you so much.
#include <iostream>
#include <string>
using namespace std;
enum exercise { push_ups, sit_ups, squats, walking, radio_calisthenics };
istream& operator>>(istream& is, exercise& i)
{
int tmp;
if (is >> tmp)
i = static_cast<exercise>(tmp);
return is;
}
int main()
{
exercise a;
cin >> a;
cout << a << endl;
}
Upvotes: 1
Views: 454
Reputation: 3956
I am trying to output a element of enum I declared but for example, when I input
push_ups
, it outputs a number like8621623
instead of showingpush_ups
.
In the operator>>
overload, std::cin
accepts integers so push_ups
isn't an integer, so std::cin
will fail and and the line i = static_cast<exercise>(tmp);
will be skipped making a
uninitialized which when printed can cause Undefined Behavior to occur.
If you want to map strings to respective enum values, you could do that by mapping each string to the corresponding enum values manually using a hashmap (In C++, that container is called std::unordered_map
):
#include <unordered_map>
// ...
const unordered_map<string, exercise> exercise_map {
{ "push_ups", push_ups },
{ "sit_ups", sit_ups },
{ "squats", squats },
{ "walking", walking },
{ "radio_calisthenics", radio_calisthenics }
};
istream& operator>>(istream& is, exercise& i) {
std::string tmp;
if (is >> tmp) {
auto const it = exercise_map.find(tmp);
if (it != exercise_map.end())
i = it->second;
}
return is;
}
Now, to print out the corresponding string value from the enum, we have to do the reverse, i.e., find the key in the hashmap using the value:
ostream& operator<<(ostream& os, exercise& i) {
auto const it = std::find_if(exercise_map.begin(), exercise_map.end(),
[i](std::pair<std::string, exercise> const& e) {
return e.second == i;
}
);
if (it != exercise_map.end())
os << it->first;
return os;
}
This is how the full code should look like:
#include <unordered_map>
#include <algorithm>
#include <utility>
#include <iostream>
#include <string>
using namespace std;
enum exercise { push_ups, sit_ups, squats, walking, radio_calisthenics };
const std::unordered_map<std::string, exercise> exercise_map {
{ "push_ups", push_ups },
{ "sit_ups", sit_ups },
{ "squats", squats },
{ "walking", walking },
{ "radio_calisthenics", radio_calisthenics }
};
istream& operator>>(istream& is, exercise& i) {
std::string tmp;
if (is >> tmp) {
auto const it = exercise_map.find(tmp);
if (it != exercise_map.end())
i = it->second;
}
return is;
}
ostream& operator<<(ostream& os, exercise& i) {
auto const it = std::find_if(exercise_map.begin(), exercise_map.end(),
[i](std::pair<std::string, exercise> const& e) {
return e.second == i;
}
);
if (it != exercise_map.end())
os << it->first;
return os;
}
int main() {
exercise a;
cin >> a;
cout << a << endl;
}
Upvotes: 1
Reputation: 3902
You seem to have problems with understanding enum
s.
I think you entered the string value "push_ups" and assumed the program would understand it to refer to a value of your enum
.
An enum
is just a placeholder for an integer type, mostly used to increase the readability of your program.
See an enum to be a better way to express something like
// chess_piece = 1 : pawn
// chess_piece = 2 : rook
// chess_piece = 3 : bishop
...
int chess_piece;
as
enum ChessPiece { Pawn, Rook, Bishop, ...};
ChessPiece chess_piece;
In the upper variant, it is clear that the names pawn, rook etc are comment only. The enum
isn't different in that regard. It is clearly more readable to write if(chess_piece == Pawn)
, but the word "Pawn" is only a part of the code in the programming language, not in the compiled program. It does not exist as string value.
What you can do is to add something like
exercise exercise_from_string(const std::string& input)
{
if(input == "push_ups") return push_ups;
...
Or the same with a switch. I'd also advise that you have a value "unknown" in case a function like that finds no known term.
Edit: One of the other guys updated his answer while I wrote this, his code using a std::map
is better than mine.
Hope my answer helps you understanding the core issue, though.
Upvotes: 0
Reputation: 48258
this line here:
i = static_cast<exercise>(tmp);
will work perfectly when tmp is holding an int value between 0 and 4,
but in your case tmp = push_ups is breaking the cast operation and your ref i is wrongly initialized
Upvotes: 0
Reputation: 37549
push_ups
is not a valid integer value that you are trying to read at is >> tmp
so a
remains uninitialized. If you want to input names then you'll need to read string and then manually convert it to corresponding enum value. Same for output. Without a properly overloaded operator << a
will be treated as an integer.
Upvotes: 1