String to enum

Started by
7 comments, last by Mizipzor 15 years, 9 months ago
Ive seen a lot of programs using enums in txt based config files. Like this, I have two enums;
enum KEYS
{
   W, S, A, D
}

enum ACTIONS
{
   FORWARD, LEFT, BACK, RIGHT
}
Then I, in the config file do this: W = FORWARD To tie a key to an action. What I want to know is what you think would be the best way to connect the string based "enum" from the textfile to the actual enum in the program. I was thinking a simple std::string array:
std::string KEY_STR[] =
{
   "W", "S", "A", "D"
};
Any other ideas?
Advertisement
std::map?

Alternatively you have an O(1) look up where you have an array that maps an action to a key code.
You can overload operators for enums, so I often overload operator<< and operator>>. Something like this:

enum Key{   W, S, A, D};std::ostream& operator<<(std::ostream& os, Key k){   switch(k)   {      case W: os << "W"; break;      case S: os << "S"; break;      case A: os << "A"; break;      case D: os << "D"; break;   }}std::istream& operator>>(std::istream& is, Key& k){    std::string t;    is >> t;    if(t == "W") k = W;    else if(t == "S") k = S;    else if(t == "A") k = A;    else if(t == "D") k = D;}


I have a Python script somewhere that generates the above code given a list of enum names but I can't find it.
Quote:Original post by Simian Man
You can overload operators for enums, so I often overload operator<< and operator>>. Something like this:

*** Source Snippet Removed ***

I have a Python script somewhere that generates the above code given a list of enum names but I can't find it.


Good idea. But wouldnt I then be forced to do a second function to get the actual string rather than a stream? Streams arent all that ideal to work with if you want to compare strings.

std::string EnumToString( Key& k ){	std::stringstream str;	str << k;	return k.str();}


And how fast is this? Allocating and deallocating streamobjects, the switch statement.

Maybe the std::map approach is better, although its not as nice code-wise.
Quote:Original post by Mizipzor
Good idea. But wouldnt I then be forced to do a second function to get the actual string rather than a stream? Streams arent all that ideal to work with if you want to compare strings.


But you don't need to compare strings, you read in the value as an enum (via the operators which do the string to enum conversion). And given that your original question asked about reading strings from a file and converting to an enum, his solution works.

Quote:Original post by Mizipzor
And how fast is this? Allocating and deallocating streamobjects, the switch statement.


Why would you ever need to compare those strings? compare the enum values surely? I think you are missing the point of the code Simian Man posted maybe? Generally any string to/from enum operation is going to be moderately costly, but for a one off config load portion of code, you're never going to care.
Quote:Original post by Mizipzor

Good idea. But wouldnt I then be forced to do a second function to get the actual string rather than a stream? Streams arent all that ideal to work with if you want to compare strings.


You're operating with files during initialization:
  std::ifstream f("config.txt");  while (...) {    Keys key;    Actions action;    f >> key;    f >> action;        // bind the key/action pair in your application  }


Quote:And how fast is this? Allocating and deallocating streamobjects, the switch statement.


Let's not worry about this right now.



What is your real problem? File IO, reading and storing these values? Building a key-mapping class? Organizing how actions are performed?

Original post suggests you're looking for a way to read configuration files.


Quote:You can overload operators for enums, so I often overload operator<< and operator>>. Something like this:


You're missing error handling, either Unknown enum value, or exception being thrown.

As it is, the >> operator can return undefined value, and << can do a nop, which would corrupt the file.
Quote:Original post by Antheus
You're missing error handling, either Unknown enum value, or exception being thrown.

As it is, the >> operator can return undefined value, and << can do a nop, which would corrupt the file.


Yeah you're right. My enum generator script (here if anyone's interested) does do those things. I don't think handling exceptions from the input stream to be necessary though. That's something that the calling code should worry about.

I agree that the OP should qualify what he needs help with though. Personally I would use the std::map for actually storing the bindings.
If you want to write the list of elements in the enum only once, you can use the preprocessor in the following ugly way:
#include <iostream>#define KEYS_ENUM_DEFINITION ENUM_DEF(W), ENUM_DEF(S), ENUM_DEF(A), ENUM_DEF(D)#define ENUM_DEF(X) Xenum KEYS {KEYS_ENUM_DEFINITION};#undef ENUM_DEF#define ENUM_DEF(X) #Xconst char *key_strings[] = {KEYS_ENUM_DEFINITION};#undef ENUM_DEFstd::ostream &operator<<(std::ostream &os, enum KEYS k) {  return os << key_strings[k];}int main() {  enum KEYS k=A;  std::cout << k << '\n';}


I don't know if this has anything to do with what the OP wants, but I thought I would throw the idea in here while we are talking about this type of problem.
Thanks for the script Simian Man!

Now, to clear it up; what I want to is to have attributes in a file, in some cases defined by other attributes. I think an rpg game is a better example than the key bindings (dont care about the math for now, its another problem);

ATTR_STR = 50
ATTR_DEX = 20
ATTR_ATK = ATTR_STR * ATTR_DEX + 100

A file looking like this would be easy to parse with the operator>>. So that part of the problem is solved.

But say I had an xml file defining items or something (point is, I have the enums in the xml file);

<root>  <item type="somethingcool">    <requirements key="ATTR_STR" val="40" />  </item></root>


Consider the initial problem solved - reading enums from a simple config file - but now the next problem is how to handle the enums in the xml files. I use TinyXml which lets me retrieve them as a std::string or const char* and therefor I need some way of using the operator (see my second post) or a second way of doing the conversion.

Either that, or I come up with a way of defining the items without xml. Maybe define my own file format? That way, I could read the enums with the operator.

Any thoughts? Sorry about being unclear before.

This topic is closed to new replies.

Advertisement