Thread: How to map enums to their string representation globaly?

  1. #1
    Registered User
    Join Date
    Nov 2006
    Posts
    519

    How to map enums to their string representation globaly?

    Hi,

    in my programs I often use enums for integer constants:

    Code:
    // directions.h
    
    enum Directions
    {
      west=1,
      south=2,
      east=3,
      nord=4
    };
    That .h file maybe gets includet in various .cpp files and the enum is used in different classes.
    No I sometimes come to the point there I want to display the enum value, so I have to map them somewhere to their string representation.

    best thing I came up with yet is to have a std::map<int, string> class memeber in each class what needs the enum-string-representation. the map is filled in the classes ctor.

    now that's not a very clear solution because of the redundant code.

    I wonder if their is a better solution to this problem or some well known idiom?

    Thanks for your ideas!

  2. #2
    Ethernal Noob
    Join Date
    Nov 2001
    Posts
    1,901
    either that or a switch case block.

  3. #3
    Massively Single Player AverageSoftware's Avatar
    Join Date
    May 2007
    Location
    Buffalo, NY
    Posts
    141
    Make a map<Directions, string> that contains all the values, and then:

    Code:
    ostream &operator << (ostream &out, Directions d)
    {
        out << DirectionMap[d];
        
        return out;
    }
    Something like this will allow you to directly print the string values, and adding a new direction is just a matter of adding it to the map.
    There is no greater sign that a computing technology is worthless than the association of the word "solution" with it.

  4. #4
    Tropical Coder Darryl's Avatar
    Join Date
    Mar 2005
    Location
    Cayman Islands
    Posts
    503
    I think using a map is a bit overkill.

    Here is what I typically do:
    Code:
    #include <iostream>
    #include <string>
    
    enum Directions
    {
      west=1,
      south, // i removed the rest since it's sequential
      east,
      north, // changed spelling
    };
    
    std::string direction2string[] ={"","West", "South", "East", "North"}; // added dummy value to skip 0
    
    
    int main ()
    {     
         std::cout << direction2string[west] <<std::endl; 
         std::cout << direction2string[south] <<std::endl; 
    
    }

  5. #5
    Registered User
    Join Date
    Nov 2006
    Posts
    519
    Thanks for you replies. But my question wasn't about the output in the first place (it's displayed in a gui most of the time).

    the thing that bothers me is that the map<int, string> or the string array like in Darryls explanation has to be built in every single class what wants "to know" the string representation of the enum values. So if I have three classes I have 3 times the same bunch of code in the ctor. and if the enum changes, I have to change 3 classes. and if I forgot one, or switch the sequence of two enum values in one class by accident I run into trouble.

    So I'm looking for a more central place to keep that string representation data. Sorry for making this not clear enough in my first post (I'm not a natural speaker).

  6. #6
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    I would make a header file with an enum and a global function declaration (perhaps in a namespace if you are using namespaces). The function would take the enum as a parameter and return a string. Then in a source file define the function to use your map or array or switch to return the proper string. If you use the map or array solution, define it in that source file in an unnamed namespace so it is local to that file.

    This way the other code can use the enum and call the function, yet all that code will be written and maintained in one place.

  7. #7
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    In Effective C++, Third Edition, Item 18, Scott Meyers suggests creating a full fledged class for a case that seems like the one you are facing. A possible adaptation of his suggestion would be:
    Code:
    class Direction
    {
    public:
        static Direction west()
        {
            return Direction(1);
        }
        static Direction south()
        {
            return Direction(2);
        }
        static Direction east()
        {
            return Direction(3);
        }
        static Direction north()
        {
            return Direction(4);
        }
    
        // ... other member functions ...
    
    private:
        // prevent creation of new Direction values
        explicit Direction(int d) : direction(d) {}
        // Direction specific data
        int direction;
    };
    In this case, the class would pretty much be global, but rather safely so.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  8. #8
    Tropical Coder Darryl's Avatar
    Join Date
    Mar 2005
    Location
    Cayman Islands
    Posts
    503
    Quote Originally Posted by pheres View Post
    Thanks for you replies. But my question wasn't about the output in the first place (it's displayed in a gui most of the time).

    the thing that bothers me is that the map<int, string> or the string array like in Darryls explanation has to be built in every single class what wants "to know" the string representation of the enum values. So if I have three classes I have 3 times the same bunch of code in the ctor. and if the enum changes, I have to change 3 classes. and if I forgot one, or switch the sequence of two enum values in one class by accident I run into trouble.

    So I'm looking for a more central place to keep that string representation data. Sorry for making this not clear enough in my first post (I'm not a natural speaker).
    What ever container holds the strings, map in your case or the array in mine can be used in another file with extern, just as you would any other global variable.

    **EDIT**
    Just looking at Daved's post, take my direction2string, wrap it in a function with the protype in the header

    Code:
    In your header 
    direction.h
    enum Directions
    {
      west=1,
      south=2,
      east=3,
      nord=4
    };
    
    std::string dir2str(Directions d);
    
    in your implementation
    direction.cpp
    
    std::string dir2str(Directions d)
    {
         std::string direction2string[] ={"","West", "South", "East", "North"};
         return direction2string[d];
    }
    Now you just include the header and call wherever needed
    Last edited by Darryl; 07-06-2007 at 02:57 PM. Reason: Read Daved's post

  9. #9
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Actually, is there any good reason to start the numbering from 1 instead of 0 for the case of the enum? Even in my suggested solution the actual values of the numbers do not really matter, and starting from 0 will make using an array of names easier. The downside to using an enum as opposed to a class is that it is less typesafe, methinks.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  10. #10
    Tropical Coder Darryl's Avatar
    Join Date
    Mar 2005
    Location
    Cayman Islands
    Posts
    503
    Quote Originally Posted by laserlight View Post
    The downside to using an enum as opposed to a class is that it is less typesafe, methinks.
    I don't think it's any less typesafe than a class and possibly more, because the values are constants.

  11. #11
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    I don't think it's any less typesafe than a class and possibly more, because the values are constants.
    The use of (static) member functions as opposed to objects to represent the values means that the 'values' are effectively constants too.

    What I had in mind was more of the
    Code:
    int s = south;
    kind of thing, though I suppose it is not particularly likely to happen by mistake.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  12. #12
    l'Anziano DavidP's Avatar
    Join Date
    Aug 2001
    Location
    Plano, Texas, United States
    Posts
    2,743
    Basically I kind of echo what laserlight has been saying. Make a class, and then that class may be used by any other class in your project.

    Even if you don't want to make it an entire class, I would still take that code out and put it in a separate "common" header file that all your classes have access to. Most projects usually have some type of file called "common.h" or "shared.h" which is just a file that has tons of stuff in it that everything wants to use.

    By the way, I noticed that in your first post, you spelled "north" as "nord". What country do you come from? sei italiano?
    My Website

    "Circular logic is good because it is."

  13. #13
    Hurry Slowly vart's Avatar
    Join Date
    Oct 2006
    Location
    Rishon LeZion, Israel
    Posts
    6,788
    And you class may also want to load strings from resources - so it will be easier later to switch to another language
    All problems in computer science can be solved by another level of indirection,
    except for the problem of too many layers of indirection.
    – David J. Wheeler

  14. #14
    Registered User
    Join Date
    Nov 2006
    Posts
    519
    Thank you all for that inspiring discussion!

    That are two very reasonable solutions so far. I'm still not shure what to prefer: laserlights class with the static functions or Darryls global function. I'll probably try the class, because there I have to "touch" every value only one time.
    Thing is I have some enums here with more than 100 values in it. So I better write a converter program. finally a reason to learn about boost::regex

    two questions remains to me. first

    Code:
    std::string dir2str(Directions d)
    {
         std::string direction2string[] ={"","West", "South", "East", "North"};
         return direction2string[d];
    }
    If I would want to use a std::map instead of the array, could it also be initialized in a similar fashion like the array above?
    Code:
         std::map<int,string> directions = . . .  ;
    Second: what's the thing with the "load strings from resources"? I know that the microsoft c++ compiler use resource files and in wxwidgets I've seen that too. But are there some portable resource files? Or do you just mean to read the strings from a file with a format I choose?


    "nord" comes more from the country in the north of italy

  15. #15
    Tropical Coder Darryl's Avatar
    Join Date
    Mar 2005
    Location
    Cayman Islands
    Posts
    503
    1st - No you can't initialize maps with an initialization list. As a matter of fact, you can't with any of the standard template containers which is an issue I think they are addressing in the new standard.

    Now, here's my arguements for enums.

    1. Ease of implemenation - You'd have to write a function for each "value" you want which as you've already stated, with hundreds could be a lot.

    2. Maintenance and error proneness. - Because you have to assign each integer value, a class with hundreds of values is more prone to duplicates, either by careless assignment or typo whereas enum value assignment is automatic. Inserting a value in between other values would be quite difficult for the static functions.

    3. Efficiency - Every time you change a direction, with the static method you create a new temp object which calls a constructor, destructor and assignment operator.

    That's all I can think of now. :-)
    Last edited by Darryl; 07-08-2007 at 09:22 AM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. String, Pair and Map Problem
    By dream_noir in forum C++ Programming
    Replies: 3
    Last Post: 02-19-2009, 07:46 PM
  2. String Class
    By BKurosawa in forum C++ Programming
    Replies: 117
    Last Post: 08-09-2007, 01:02 AM
  3. We Got _DEBUG Errors
    By Tonto in forum Windows Programming
    Replies: 5
    Last Post: 12-22-2006, 05:45 PM
  4. Message class ** Need help befor 12am tonight**
    By TransformedBG in forum C++ Programming
    Replies: 1
    Last Post: 11-29-2006, 11:03 PM
  5. can anyone see anything wrong with this code
    By occ0708 in forum C++ Programming
    Replies: 6
    Last Post: 12-07-2004, 12:47 PM