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

  1. #16
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    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.
    I believe that an enum with hundreds of posible values would have the same problem. After all, we are talking of what are likely to be a one-liner functions.

    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.
    I think that we have to take this into perspective. Are we likely to use this with hundreds of values? Meyers' example was with dates, in particular a Month class. There are only twelve months in a year, and this status quo is likely to stay for the duration of our lifetimes. Likewise, there are four cardinal directions, and this is not likely to change either.

    I note that Meyers' example corresponds very closely to the integers that the static member functions are supposed to replace (e.g., we usually designate January as month 1). But there is no precedent by which west should be 1 and south 2. So, having an enum in which the values are not explicitly given makes more sense than arbitrarily assigning values. On the other hand, if we see that we might want to add the ordinal directions, or even all the principal compass points, then using the compass point angles to provide integer values could well be an even better solution.

    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.
    I agree, but the objects in question are not likely to be heavyweight in construction, assignment and destruction, and this factor may even prove to be negligible.
    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

  2. #17
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    In fact, since the constructor is inline and trivial, and copy construction, copy assignment and destruction are all trivial and auto-generated, there is no reason to assume that there is any overhead at all in using the class.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  3. #18
    Tropical Coder Darryl's Avatar
    Join Date
    Mar 2005
    Location
    Cayman Islands
    Posts
    503
    I think that we have to take this into perspective. Are we likely to use this with hundreds of values? Meyers' example was with dates, in particular a Month class.
    I did take it into perspective based on this reply from the original poster
    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
    Even 1 line functions will still get a bit unwieldy when you get up into a hundred, here's just 26 to make my point

    Code:
    enum alpha { a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z};
    Versus

    Code:
    class alpha{ 
    public:
    static alpha a(){return alpha(1);}
    static alpha b(){return alpha(2);}
    static alpha c(){return alpha(3);}
    static alpha d(){return alpha(4);}
    static alpha e(){return alpha(5);}
    static alpha f(){return alpha(6);}
    static alpha g(){return alpha(7);}
    static alpha h(){return alpha(8);}
    static alpha i(){return alpha(9);}
    static alpha j(){return alpha(10);}
    static alpha k(){return alpha(11);}
    static alpha l(){return alpha(12);}
    static alpha m(){return alpha(13);}
    static alpha n(){return alpha(14);}
    static alpha o(){return alpha(15);}
    static alpha p(){return alpha(16);}
    static alpha q(){return alpha(17);}
    static alpha r(){return alpha(18);}
    static alpha s(){return alpha(19);}
    static alpha t(){return alpha(20);}
    static alpha u(){return alpha(21);}
    static alpha v(){return alpha(22);}
    static alpha w(){return alpha(23);}
    static alpha x(){return alpha(24);}
    static alpha y(){return alpha(25);}
    static alpha z(){return alpha(26);}
    //... rest of implementation
    };

  4. #19
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    Regex and an external converter might be overkill. Boost.Preprocessor should be able to do all the preprocessing. Someone wrote a smart enum class for Boost. It should be in the vault.
    http://boost-consulting.com/vault/
    Scroll down to enum_rev4.6.zip and try it out. At least it should contain some ideas.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  5. #20
    Registered User manofsteel972's Avatar
    Join Date
    Mar 2004
    Posts
    317
    I was bored and this was kind of interesting. I did a bit of looking around and found this link http://www.edm2.com/0405/enumeration.html In it they create a custom insert operator for the string class to format the text output for the enum. Perhaps it may help.
    "Knowledge is proud that she knows so much; Wisdom is humble that she knows no more."
    -- Cowper

    Operating Systems=Slackware Linux 9.1,Windows 98/Xp
    Compilers=gcc 3.2.3, Visual C++ 6.0, DevC++(Mingw)

    You may teach a person from now until doom's day, but that person will only know what he learns himself.

    Now I know what doesn't work.

    A problem is understood by solving it, not by pondering it.

    For a bit of humor check out xkcd web comic http://xkcd.com/235/

  6. #21
    Registered User
    Join Date
    Nov 2006
    Posts
    65
    Here's one way that stops data duplication.

    In my_enum.H
    Code:
    MY_MACRO_NAME(SSSE,
                  "Almost South, with a bit of East.", /* just a description */
                  "Any other detail anyone may find useful anywhere at anyime")
    MY_MACRO_NAME(SSSW,
                  "Amlost South, with a bit of West.", /* just a description */
                  "Any other detail anyone may find useful anywhere at anyime")
    In my_header.H
    Code:
    #include <string>
    #include <iostream>
    
    enum my_enum {
       if_you_do_not_want_to_start_at_0_then_use_this = 10,
    
    #define MY_MACRO_NAME(x, ...) x,
    #include "my_enum.H"
    
       you_can_use_this_to_get_an_automatic_member_count_plus_offset
    };
    
    std::string enum_as_string(my_enum enum_numeric)
    {
       switch(enum_numeric) {
    
    #undef MY_MACRO_NAME
    
    #define MY_MACRO_NAME(x, ...)                \
       case x:                                   \
          return(# x);                           \
          break;
    
    
    #include "my_enum.H"
    
    
       default:
           return("something bad");
       }
    
    }
    And a test program, test.cpp:
    Code:
    #include "my_header.H"
    
    int main()
    {
       std::cout << enum_as_string(SSSE) << std::endl; // "SSSE"
       std::cout << enum_as_string(SSSW) << std::endl; // "SSSW"
       return(0);
    }
    You should be able to work out how to make a function which returns the description, in a very similar way. Also, if necessary, it should be possible to extend this so that you specify the numeric value of each enum member, but that seems very pointless, in my opinion.

  7. #22
    Registered User
    Join Date
    Nov 2006
    Posts
    519
    I looked at my code today and remembered on another feature my string representation has to provide: iteration over it. Finally I decided to try to use an enum and a class like this:


    Code:
    #ifndef DEM_SWRMCOMMANDS_H
    #define DEM_SWRMCOMMANDS_H
    
    #include <map>
    
    #include "Singleton.h"
    
    using namespace std;
    
    namespace dem {
    
    enum SwrmCmds
    {
      RMCMD_EM_ONLINE,
      RMCMD_MY_ENTITY,
      RMCMD_EM_SHUTDOWN,
      RMCMD_SYSTEM_SHUTDOWN,
      RMCMD_NEW_ENTITY,
      RMCMD_INSTANTIATE_ENTITY,
      RMCMD_REMOVE_ENTITY,
      RMCMD_SHUTDOWN_SYSTEM,
      RMCMD_STOP_ENTITY,
      RMCMD_START_ENTITY,
      RMCMD_IMCOMMAND,
      RMCMD_TRANSFER_ENTITY,
      RMCMD_TRANSFER_READY,
      RMCMD_TRANSFER_COMPLETE,
      RMCMD_CONTINUE_UPDATE
    
    };
    
    class SwrmCommands : public Singleton<SwrmCommands>
    {
    
    public:
    	
    	SwrmCommands()
    	
    	:swrmCmd2stringMap()
    	
    	{
    	    // build swrmCmd2string map
    	    swrmCmd2stringMap[RMCMD_EM_ONLINE] =
    	    	"RMCMD_EM_ONLINE";
    	    swrmCmd2stringMap[RMCMD_MY_ENTITY] =
    	    	"RMCMD_MY_ENTITY";
    	    swrmCmd2stringMap[RMCMD_EM_SHUTDOWN] =
    	    	"RMCMD_EM_SHUTDOWN";
    	    swrmCmd2stringMap[RMCMD_SYSTEM_SHUTDOWN] =
    	    	"RMCMD_SYSTEM_SHUTDOWN";
    	    swrmCmd2stringMap[RMCMD_NEW_ENTITY] =
    	    	"RMCMD_NEW_ENTITY";
    	    swrmCmd2stringMap[RMCMD_INSTANTIATE_ENTITY] =
    	    	"RMCMD_INSTANTIATE_ENTITY";
    		swrmCmd2stringMap[RMCMD_REMOVE_ENTITY] =
    	    	"RMCMD_REMOVE_ENTITY";
    	    swrmCmd2stringMap[RMCMD_SHUTDOWN_SYSTEM] =
    	    	"RMCMD_SHUTDOWN_SYSTEM";
    	    swrmCmd2stringMap[RMCMD_STOP_ENTITY] =
    	    	"RMCMD_STOP_ENTITY";
    	    swrmCmd2stringMap[RMCMD_START_ENTITY] =
    	    	"RMCMD_START_ENTITY";
    	    swrmCmd2stringMap[RMCMD_IMCOMMAND] =
    	    	"RMCMD_IMCOMMAND";
    	    swrmCmd2stringMap[RMCMD_TRANSFER_ENTITY] =
    	    	"RMCMD_TRANSFER_ENTITY";
    	    swrmCmd2stringMap[RMCMD_TRANSFER_READY] =
    	    	"RMCMD_TRANSFER_READY";
    	    swrmCmd2stringMap[RMCMD_TRANSFER_COMPLETE] =
    	    	"RMCMD_TRANSFER_COMPLETE";
    	    swrmCmd2stringMap[RMCMD_CONTINUE_UPDATE] =
    	    	"RMCMD_CONTINUE_UPDATE";		
    	}
    	
    	const map<int, string>& getSwrmCmd2stringMap() const
    	{
    		return swrmCmd2stringMap;
    	}
    	
    private:
    	
    	map<int, string> swrmCmd2stringMap;
    	
    };
    
    } // namespace dem
    
    #endif // DEM_SWRMCOMMANDS_H
    Singleton is just my template class that transforms a normal class into a singleton. So I get strings like this:

    Code:
    string str = SwrmCommands::instance().getSwrmCmd2StrMap()[enum-value];
    So I have got now
    - a global enum for the integer constants
    - a single global static object holding the mapped string representations
    - unlike as in the string array the map is only filled one time per program run, not every time someone asks for a string representation

    What do you think?




    As a side question:

    The getter function of that class returns a const reference. But how can I lookup in it? Operator[] does not work because there is no const version of it, operator[] does always insert if no data value is found yet for the key looked up.
    The gnu stl implementation I use defines a member
    Code:
    at(const keytype&) const
    for maps that does the job, but I can't find it at the sgi reference http://www.sgi.com/tech/stl/Map.html so it's probably not standard.
    Last edited by pheres; 07-09-2007 at 03:09 AM.

  8. #23
    Tropical Coder Darryl's Avatar
    Join Date
    Mar 2005
    Location
    Cayman Islands
    Posts
    503
    What do you think?
    Not bad :-) I would have mapped the enum instead of the int (map<int, string> swrmCmd2stringMap; ) , but maybe you are planning on passing it integers as well as enums.

    I still like the simplicity of the string array, you could have declared it static or even made it a member variable. like you did the map if you wanted to avoid the overhead of it being created every function call.

    As far as your side question, I think you should return the string and not the map since it's really the string you are after.
    Code:
    string getSwrmCmd2string(SwrmCmds enumvalue ) const
    {
         if (swrmCmd2stringMap.find(enumvalue) != swrmCmd2stringMap.end())
              return swrmCmd2stringMap[enumvalue];
         else 
              return "Invalid";
    }
    If you really need the map, at() is non-standard and [] is an insert operator, hence no const version, so that leaves you with find()

    Code:
    const map<int, string> StrMap_copy = SwrmCommands::instance().getSwrmCmd2StrMap();
    
    map<int, string>::const_iterator it = StrMap_copy.find(enum_value);
    
    if ( it != StrMap_copy.end())
    { 
         str = it->second;
    }
    else
    //enum/string not found

  9. #24
    Registered User
    Join Date
    Nov 2006
    Posts
    519
    You are right, I also have to pass int (received as char array over network and then casted back and parsed) to the map, so I can't alter the type, even if it would look cleaner.

    The reason I return the whole map and not just the string is the need to list all enums (as strings) in a choice gui element, so iteration over the map is needed. (I'm writing a dedicated debugger next to my program to test and review it extensively. And in the debugger-gui you can choose all things to send over network to test the reaction. just to explain the reason why I need this.)

    Ok, so I'll ban the non-portable map::at() from my code and use your example with find. Thank you!

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