Enum iteration and enum to text?

Started by
8 comments, last by stormrunner 19 years, 1 month ago
I have an enum like so: enum WEAPONS { WEAPON_GUN, WEAPON_KNIFE, etc.. } I was wondering if there was a way to iterate through that and convert the enum names to text.
Advertisement
Not to my knowledge, though placing something like this right below:
char *weaponnames[]={"weapon_gun","weapon_knife"...};


Allows nice things like this to occur:

cout << weaponnames[player->weapon];


or

for (int x=0;x<WEAPON_MAX;x++){      if (somestring==weaponnames[x]){             return((WEAPONS)(x));      }}
Well, if it helps, each enum value has a number value attached to it. You can designate the start number like this:

enum WEAPONS {WEAPON_GUN = 1,WEAPON_KNIFE,etc...};


So I'm guessing you could just iterate through them with a for loop, but I'm not completely sure. About giving each one a name, can't help you there, you probably will just have to hard code it. As for the for loop maybe something like this:

for(i = 0; i < MAX_WEAPONS; i++)    weapon = (WEAPONS)i;


That probably won't work though...



-----------------------------Play Stompy's Revenge! Now!
You can't really "iterate through" an enumeration, because well... there aren't any "things" there to iterate over. (However, since each enumerated value corresponds to a numeric value, you can use a for loop with those values - but those would just be indices; you'd still need an array to index into.) And you can't get the names at runtime, because they don't exist at runtime - those names are just symbol names for the compiler; you can no more access them than you could the names of your variables.

One of the reasons for using enumerations in C++ is that they create a new type. (You can implicitly convert an enumeration value to an integer, but the reverse conversion requires an explicit cast in C++, and heaven help you if you use an invalid integer value there. Oh, in C that conversion does not require an explicit cast.) So, one option is to make a more involved type, using a class:

class Weapon {  int type;  static std::vector<std::string> names;  static int len;  void init();  public:  Weapon(int type = 0) : type(type) {    if (type < 0 || type >= len) {      throw std::range_error("Invalid weapon type");    }  }  Weapon(const std::string& name) {    for (int i = 0; i < len; i++) {      if (names == name) { type = i; return; }    }    throw std::logic_error("No weapon with that name");  }     // Once created, we can see the object's name, but not its ID -  // although we can compare the objects - and can't change its data.  std::string& name() { return names[type]; }  static int numTypes() { return names.length(); }}void Weapon::init() {  names = vector();  names.push_back("gun");  names.push_back("knife");  // etc.  len = names.length();}// later:Weapon w(1);Weapon w2("knife");if (w == w2) { cout << "Weapon 1 is a knife." << endl; }cout << "Weapon 0's name: " << Weapon().name();cout << "There are " << Weapon::numTypes() << " weapons to choose from.";


All off the top of my head, no guarantees of correctness, efficiency, safety or sanity.
You can also use std::map... (haven't used it much, but I think its rather good)
 std::map<WEAPONS,std::string> strWeapons;

However, I have not yet learned how to use std::map, so you're going to have to search for that, and tell me if you find any good articles.
Projects:> Thacmus - CMS (PHP 5, MySQL)Paused:> dgi> MegaMan X Crossfire
So basically the answer is no? :)
All of the methods are basically hard coded text, which is what I'm currently using. I was hoping to get away from that, but alas that doesn't seem possible.

Oh well, thanks anyway.
I don't think you quite understand why you'd use an enum. It basically takes a plan old number and makes it so that you can understand it easier. So, instead of having something like this:
int weapontype = 3;  // make the weapon type a saw}
You could have something like this:
enum WEAPONS{ WEAPON_GUN, WEAPON_KNIFE, WEAPON_SAW }int weapontype = WEAPON_SAW; // More understandable?
Rob Loach [Website] [Projects] [Contact]
Quote:
I don't think you quite understand why you'd use an enum.


I do, actually. But that has nothing to do with why I want to conver them to text.

I'm looking to convert enum names into text for my map editor. It'd certainly be easier than showing numbers (the enums actual values) or having to hard code a bunch of text names for each enum.
having a corressponding array of strings is a pretty common method. You just have to make sure that they always match up (I usually put a comment above the enum saying that the string list will need to be modified if the enum is modified, on pain of death -_^).

Also, its handy to always have a "count" item as the last enum. eg.

// O M F G BE SURE TO UPDATE WEAPON_NAMES IF YOU MODIFY THIS OTHERWISE CARNAGE WILL ENSUEenum WEAPONS{WEAPON_GUN,WEAPON_KNIFE,...WEAPON_COUNT}const char* WEAPON_NAMES[WEAPON_COUNT] = { "gun", "knife", ... };


then you can define an array of weapons, and iterate accross them:

Weapon weapons[WEAPON_COUNT];for (int i = 0; i < WEAPON_COUNT; i++)  { blah; }

- Thomas Cowellwebsite | journal | engine video

Quote:Original post by wyrd
So basically the answer is no? :)
All of the methods are basically hard coded text, which is what I'm currently using. I was hoping to get away from that, but alas that doesn't seem possible.

Well, you could make an enum wrapper - essentially a wrapper over an std::map. It's simple, but it's dynamic and you could reuse it for other enums, especially if you've assigned a certain enum group a certain type.
#include <map> // include std::map, obviously#include <string> // include std::string// enums of itemsenum eItem {   eWeapon,   ... other enums};template<typename T>class EnumWrapper{    public:      void register(T val, std::string match); // set an enum to a string      std::string retreiveSymbol(T key); // return an std::string      T retreive(std::string val); // return the enum for this string    private:      std::map<T, std::string> m_enumMap;};// typedef for ease of usetypedef EnumWrapper<Item> ItemEnums;// make it a globalItemEnums _itemList;

You could read the names from a file, and register them that way -
if(_enum == eWeapon) { _itemList.register(_enum, "Teh Weapon of Dhoom !!!"); }

Food for thought.
- stormrunner

This topic is closed to new replies.

Advertisement