Seeking code for temple for a <map> of enum to string

B

Baron Samedi

I know that it's an old one - how to take an enum value and output a
string.

I'd like to make it a template class, so that I can add to it in a
general manner.

I would also like to be able to extend it later.

I am stumped!!

Any ideas?

Thanks in advance for any help
 
S

SG

I know that it's an old one - how to take an enum value and output a
string.

....with a std::map you mean? Well, it's not that hard.
I'd like to make it a template class, so that I can add to it in a
general manner.

Huh? "make it a template class"? You don't need to write another
implementation. Just use the one provided in the header said:
I would also like to be able to extend it later.

Extend WHAT and HOW?
I am stumped!!
Any ideas?

Did you even attempt to solve your problem on your own? At least query
a search engine or Wikipedia or something.

Cheers!
SG
 
J

James Kanze

I know that it's an old one - how to take an enum value and
output a string.

I'm assuming that you also want some relationship between the
enum value and the string. And that you want the string to be
generated automatically, mapped from the name of the enum value.

For that, you need either a compiler extension or some external
program which reads your source and generates the necessary
mappings.
I'd like to make it a template class, so that I can add to it
in a general manner.

A template can't deal with the names of things.
 
G

Guest

I know that it's an old one - how to take an enum value and output a
string.

I'd like to make it a template class, so that I can add to it in a
general manner.

I would also like to be able to extend it later.

I am stumped!!

Any ideas?

I've only seen this done with a code generator. In the case I saw,
Rational Rose.
I was never impressed with the way it actually worked and always meant
to
invent a better one. A code generator shouldn't be too dificult to
write
though.
 
J

Jorgen Grahn

I know that it's an old one - how to take an enum value and output a
string.

I'd like to make it a template class, so that I can add to it in a
general manner.

I would also like to be able to extend it later.

Is this enough? If not, why?

enum Foo { Bar, Baz, ... };

std::eek:stream& operator<< (std::eek:stream& os, const Foo& val)
{
switch(val) {
case Bar: return os << "Bar";
case Baz: return os << "Baz";
...
}
}

/Jorgen
 
A

AnonMail2005

I know that it's an old one - how to take an enum value and output astring.

I'd like to make it a template class, so that I can add to it in a
general manner.

I would also like to be able to extend it later.

I am stumped!!

Any ideas?

Thanks in advance for any help

This is a common task. Of course, inside you program, library, or
collection of libraries you want to just use your enumerator. But
what you've defined as an enumerator may come in from the external
world as text.

Textual representation also comes in handy for error messages and when
serializing data. Serializing an enumerator as an int is a future
maintenance nightmare just waiting to happen. Doing so means you
can't change the value of an emuerator without worrying about breaking
something.

What we have done is implement three template functions for each
enumerator.
Here are their signatures:

// convert a string to an enumerator - throw an exception if the
string is invalid
template <class T>
T stringToEnum (const std::string & s)

// convert a string to an enumerator
// on success, return true and set t; on failure, return false and t
is not touched
template <class T>
bool stringToEnum (const std::string & s, T & t)

// convert an enumerator to string (actually const char *)
template <class T>
const char * enumToSTring (T t);

Internally these are implemented using a static array of pairs of
const char * and enumerators. Using a static array of POD means there
are no of order of initialization or thread safety issues that you
might encounter using a std::map (for instance) or other C++ class.

Lookup is done using linear search. We've never had any performance
issues with this. When converting from string to enumerator we use
case insensitive compares. Different strings can be mapped to the
same enumerator value if needed. When converting from enumerator to
string the first entry in the array will be the "preferred" text
representation.

What's more, we've hidden all of the implementation by explicitly
instantiating each function inside the implementation file. The user
of the functions never see anything but the plain old enumerator and
the signature of the above classes.

These functions go a long way to solving the enumerator to string and
string to enumerator task. With them, writing an operator<< or
operator>> is trivial.

The code is done at work - I will ask if it is ok to post it.

HTH
 
J

James Kanze

This is a common task. Of course, inside you program,
library, or collection of libraries you want to just use your
enumerator. But what you've defined as an enumerator may come
in from the external world as text.
Textual representation also comes in handy for error messages
and when serializing data. Serializing an enumerator as an int
is a future maintenance nightmare just waiting to happen.
Doing so means you can't change the value of an emuerator
without worrying about breaking something.

Well, the obvious answer to that is "don't change them":).
Seriously, you do need some sort of versioning, even if you're
using text represtations for serialization, since you have to
deal with enum values being added and removed. (Of course, all
of the other arguments for textual representation still hold.
Reading "operationPending" for the state, rather than "5", makes
debugging considerably easier.)
What we have done is implement three template functions for each
enumerator.
Here are their signatures:
// convert a string to an enumerator - throw an exception if the
string is invalid
template <class T>
T stringToEnum (const std::string & s)
// convert a string to an enumerator
// on success, return true and set t; on failure, return false and t
is not touched
template <class T>
bool stringToEnum (const std::string & s, T & t)
// convert an enumerator to string (actually const char *)
template <class T>
const char * enumToSTring (T t);

Just a question: you have generic templates to do this? I can't
see how (but maybe I've missed something).

In my case, I use a (originally) simple program, capable of
understanding enough C++ to parse the enums, to generate the
implementations of these. Also, I've found that the template
solution poses some problems, mainly with regards to namespaces;
my solution has been to generate functions toString( EnumType )
and to<EnumType>( string ). And a third, fromString( string,
EnumType& ) for use in templates. (Having the EnumType in an
argument makes the function name dependent, and causes ADL to
kick in.) These functions are generated in the same namespace
as the enum.

I originally used the template approach, but couldn't find an
appropriate namespace to put it in. (More exactly, I orginally
implemented the code as part of my library, with the templates
in the same namespace as the library code. This version is
available at my site: http://kanze.james.neuf.fr/code-en.fr. I
have since changed the implementation to remove all dependencies
on my library in the generated code. Having done this, I didn't
want it to use the namespace Gabi, and I couldn't find another
appropriate namespace for the templates. I actually liked the
idea of naming the function templates string_cast, and putting
them in global namespace, but I was too worried about possible
conflicts with other code.)

FWIW, the current implementation has options to generate either:
Gabi::Util::Fallible< std::string > toString( enum_type ) ;
Gabi::Util::Fallible< enum_type > toenum_type( std::string
const& ) ;
bool fromString( enum_type&, std::string const& ) ;
(for myself and others using my library) or
char const* toString( enum_type ) ;
enum_type const* toenum_type( std::string const& ) ;
bool fromString( enum_type&, std::string const& ) ;
(With enum_type being the type of the enum, of course). When
all is said and done, however, I think that in this case, using
Fallible instead of pointers may be overkill.
Internally these are implemented using a static array of pairs
of const char * and enumerators. Using a static array of POD
means there are no of order of initialization or thread safety
issues that you might encounter using a std::map (for
instance) or other C++ class.

Agreed. At one point, I toyed with the idea of having two
std::map at the interface level, so that users would have a well
known interface to deal with, rather than something I define
myself. In the end, both order of initialization and naming
problems lead me to abandon this approach.
Lookup is done using linear search. We've never had any
performance issues with this. When converting from string to
enumerator we use case insensitive compares.

That's an interesting idea. Sounds like I'll have to add an
option to my generator.
Different strings can be mapped to the same enumerator value
if needed.

And different enumerators to the same string?
When converting from enumerator to string the first entry in
the array will be the "preferred" text representation.

I do a one to one mapping, but at the symbolic level (name
to/from string); if two enum constants have the same value, then
I handle it as you do---first match is used.

I also permit (in the current versions) transformations in the
name, mainly because I had code available which supported this
already, and I've encountered places which had special naming
conventions for enum constants, that you possibly wouldn't want
to appear in the external representations.
What's more, we've hidden all of the implementation by
explicitly instantiating each function inside the
implementation file. The user of the functions never see
anything but the plain old enumerator and the signature of the
above classes.

So you do have an explicit specialization for each enum. Hand
written, or automatically generated?

Note that for the code to be conform, you do need for a
declaration of the specification to be visible anytime it is
used.
These functions go a long way to solving the enumerator to
string and string to enumerator task. With them, writing an
operator<< or operator>> is trivial.
The code is done at work - I will ask if it is ok to post it.

But the code is probably simpler than defining the interface:).
A simple struct, a couple of predicates, and std::find_if should
do the trick.
 
A

Anand Hariharan

I know that it's an old one - how to take an enum value and output a
string.

I'd like to make it a template class, so that I can add to it in a
general manner.

I would also like to be able to extend it later.

I am stumped!!

Any ideas?

Thanks in advance for any help


Paul Hsieh (a regular in c.l.c) used preprocessor tricks to do what
you are after:

http://www.azillionmonkeys.com/qed/einst.c

(look at decls)

hope this helps,
- Anand
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,754
Messages
2,569,522
Members
44,995
Latest member
PinupduzSap

Latest Threads

Top