Home » Community » Forums » » Stringizing C++ Enums
  Intel sponsors gamedev.net search:   
[Control Panel] [Register] [Bookmarks] [Who's Online] [Active Topics] [Stats] [FAQ] [Search]

Add Forum to Favorites |  Send Topic To a Friend | View Forum FAQ | Track this topic


 Last Thread Next Thread 
 Stringizing C Enums
Post Reply 
Just noticed a small typo:

The first line of the code listing in the 'How does it actually work?' section is
template << struct EnumString>Master> :

It should actually be
template <> struct EnumString<Master> :

Thanks,
Francis Xavier



 User Rating: 1028   |  Rate This User  Send Private MessageView Profile Report this Post to a Moderator | Link

Hey, that's really nice work! It had never occurred to me that something like that was possible in C++. Thanks for the article!


Fully Destructible Environments in an Open Source Engine

 User Rating: 1143   |  Rate This User  Send Private MessageView Profile Report this Post to a Moderator | Link

Quote:
Original post by FrancisXavier
Just noticed a small typo

Fixed


 User Rating: 2077   |  Rate This User  Send Private MessageView ProfileView Journal Report this Post to a Moderator | Link

Nice article!

I'd actually say that the biggest disadvantage of this implementation is having to maintain two identical (redundant) enumerations -- it's error prone, and a bit of a hassle, especially for large lists.

Had you considered using x-macros? They solve the enum redundancy issue, as well as provide constant time enum-to-string lookups (as a bonus). They have their own set of disadvantages, but I personally think the trade-off is worth it here.

You could even combine your method with x-macros (in order to define the identifiers only once), and maintain the templated approach with C++ containers if you wanted.

Cheers!



 User Rating: 1043   |  Rate This User  Send Private MessageView Profile Report this Post to a Moderator | Link

Great work. I've implemented it in my engine, with some changes, and it simplified some sections of my code ALOT!

I used it in sections of my code that read script files and translate string tokens to the corresponding enum values. The solution Francis proposed allowed me to avoid a lot of if-else statements.

Thanks, Francis.

 User Rating: 1027   |  Rate This User  Send Private MessageView Profile Report this Post to a Moderator | Link

Quote:
Original post by ThrustGoblin
Nice article!

I'd actually say that the biggest disadvantage of this implementation is having to maintain two identical (redundant) enumerations -- it's error prone, and a bit of a hassle, especially for large lists.

Thanks! You're right, it is somewhat of a hassle; but this is the neatest syntax I could come up with. :(
Quote:
Original post by ThrustGoblin
Had you considered using x-macros? They solve the enum redundancy issue

The article's aim is to also provide support for existing enumerations (like those from commonly used libraries). Besides, IMHO X-Macros syntax is quite confusing to beginners.
Quote:
Original post by ThrustGoblin
as well as provide constant time enum-to-string lookups (as a bonus).

I'm probably missing something, but does it work also for enumerators with non-contiguous values?


 User Rating: 1028   |  Rate This User  Send Private MessageView Profile Report this Post to a Moderator | Link

Quote:
Original post by jcabeleira
Great work. I've implemented it in my engine, with some changes, and it simplified some sections of my code ALOT!

I used it in sections of my code that read script files and translate string tokens to the corresponding enum values. The solution Francis proposed allowed me to avoid a lot of if-else statements.

Thanks, Francis.

Thanks, I'm happy that it was of use to someone other than myself. :)

 User Rating: 1028   |  Rate This User  Send Private MessageView Profile Report this Post to a Moderator | Link

It's true the X-Macro syntax is a bit confusing at first, which is a negative aspect. But as with actual design patterns, you just need to learn it once. They are very useful and powerful in certain situations, and reduce redundancy which is what makes them worth considering. I've seen a lexical analyzer made using x-macros, for example (wouldn't necessarily suggest that, but it is definitley possible).

Using your list of masters as an example, you could have something like this (off top of my head, haven't actually compiled this):

enum Master
{
#define DeclareMaster(name, weight) name,
#include "MasterList.h"
#undef DeclareMaster
};

const char * GetMasterName(const Master master)
{   
   switch(master)   
   {
#define DeclareMaster(name, weight) case name: return #name;
#include "MasterList.h"
#undef DeclareMaster
   default:
      return "";
   }
}

unsigned int GetMasterWeight(const Master master)
{   
   switch(master)   
   {
#define DeclareMaster(name, weight) case name: return weight;
#include "MasterList.h"
#undef DeclareMaster
   default:
      return 0;
   }
}



And the MasterList.h header would simply look like:

// DeclareMaster(name, weight)
DeclareMaster(Tigress, 5)
DeclareMaster(Viper, 3)
DeclareMaster(Monkey, 4)
DeclareMaster(Mantis, 3)
DeclareMaster(Crane, 2)



The MasterList.h is meaningless by itself, since it acts like a template. The ID for each master implied (by the order in enum), and the weight/names are constant-time lookups. You could easily add more properties to the masters, as additional parameters to the DeclareMaster() macro... like height, strength etc.

Anyway, just a suggestion. Article was still very good :)

 User Rating: 1043   |  Rate This User  Send Private MessageView Profile Report this Post to a Moderator | Link

Quote:
Original post by ThrustGoblin
It's true the X-Macro syntax is a bit confusing at first, which is a negative aspect. But as with actual design patterns, you just need to learn it once. They are very useful and powerful in certain situations, and reduce redundancy which is what makes them worth considering. I've seen a lexical analyzer made using x-macros, for example (wouldn't necessarily suggest that, but it is definitley possible).

Thanks for the code snippet and info on X-Macros; it looks like a very useful method.
Quote:
Original post by ThrustGoblin
Article was still very good :)

Thank you :)

The main idea behind the article was to provide a consistent method for both new as well as existing enumerations. In the latter case, the issue of having to re-declare the enumeration becomes irrelevant. However, if you don't need string support for existing enumerations or don't mind the consistency of usage between the latter and the former, then the method you have described is very effective.


[Edited by - FrancisXavier on November 5, 2008 10:32:55 AM]

 User Rating: 1028   |  Rate This User  Send Private MessageView Profile Report this Post to a Moderator | Link

The proposed Boost.Enum library has a very nice interface for all this. (Download at the Boost Vault.)

Here are some of the examples given:
	BOOST_ENUM_VALUES(Level, const char*,

		(Abort)("unrecoverable problem") 

		(Error)("recoverable problem")   

		(Alert)("unexpected behavior") 

		(Info) ("expected behavior") 

		(Trace)("normal flow of execution") 

		(Debug)("detailed object state listings") 

	)



BOOST_ENUM_VALUES(VirtualKey, int,

	(Zero) (0)

	(Space)(0x20)

	(Prior)(0x21)

	(Next) (0x22)

	(End)  (0x23)

	(Home) (0x24)

)




It offers switch-based enum-to-string (like "Alert" or "Prior") and enum-to-value (like "expected behavior" or 0x22), and linear string-to-enum, all with no static data structures or initialization.

(And switch-based is, of course, as fast as you can get, with most compilers.)


 User Rating: 1082   |  Rate This User  Send Private MessageView Profile Report this Post to a Moderator | Link

Quote:
Original post by me22
The proposed Boost.Enum library has a very nice interface for all this. (Download at the Boost Vault.)

Here are some of the examples given:
*** Source Snippet Removed ***
*** Source Snippet Removed ***

It offers switch-based enum-to-string (like "Alert" or "Prior") and enum-to-value (like "expected behavior" or 0x22), and linear string-to-enum, all with no static data structures or initialization.

(And switch-based is, of course, as fast as you can get, with most compilers.)


I see two issues at the moment (IMHO) with Boost.Enum:

1.) The speed of conversion depends on the direction. If you're converting from enums to strings more frequently, then Boost.Enum is faster than the method provided here (switch vs. linear search respectively). If you're converting from strings to enums more frequently, then the method provided here is faster than Boost.Enum (binary vs. linear search respectively).

IMHO, strings are converted to enums more frequently (like during loading of data) than vice versa. Converting enums to strings are only required when serializing (and games usually load more data than they save) or when providing error messages to the user (which is infrequent enough for performance to not matter much). So from this point of view, the method provided here should perform better on average than Boost.Enum.

2.) Boost.Enum doesn't provide support for existing enumerations. (useful when you can't modify the code from the lib you use, like enums from SDL for e.g.)
Edit: You could namespace it, but that could create some confusion with the duplicate names in different namespaces.

Sorry for the late reply.


[Edited by - FrancisXavier on June 7, 2009 7:07:17 PM]

 User Rating: 1028   |  Rate This User  Send Private MessageView Profile Report this Post to a Moderator | Link

All times are ET (US)

Post Reply
 Last Thread Next Thread 
Forum Rules:
You may not post new threads
You may post replies
You may not edit your posts
You may not use HTML in your posts
Jump To:
Administrative Options: