By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
449,304 Members | 2,052 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 449,304 IT Pros & Developers. It's quick & easy.

smarter enums

P: n/a

i have been toying with the idea of making my enums smarter - ie, more
in line with the rest of the language. i haven't tested it yet, but what
i came up with is a template like this:

template <typename Enum>
class smart_enum
{
public:
typedef Enum enum_type;

smart_enum() {}
smart_enum(enum_type e) e_(e) {}

enum_type get() const { return e_; }

bool operator==(smart_enum const& e) const { return e.e_ == e_; }
bool operator!=(smart_enum const& e) const { return !(e_ == *this); }

operator enum_type() const { return e_; }

private:
enum_type e_;
};

i would like this to be used to transparently replace existing enum
types - with one exception. i want to disallow:

colour c = green;

and force:

colour c = colour::green;

otherwise, i want the template to behave exactly like a regular enum
type. would this template work? or am i missing anything?

the next thing i am thinking about is making the transition to smart
enums easy, using macros. something like this:

#define DEFINE_ENUM_START(enum_t) \
namespace enum_t ## _DUMB_ENUM_ { \
typedef enum
#define DEFINE_ENUM_END(enum_t) \
enum_t; } \
typedef smart_enum< enum_t ## _DUMB_ENUM_ :: enum_t > enum_t;

again, not tested or even compiled. but what i'd like to be able to do is:

DEFINE_ENUM_START(colour)
{
red,
green,
blue
}
DEFINE_ENUM_END(colour)

has anyone seen anything like this before? are there any problems with
doing this?

mark

Jul 22 '05 #1
Share this Question
Share on Google+
27 Replies


P: n/a
"Mark A. Gibbs" <x_*********@rogesr.com_x> wrote...

i have been toying with the idea of making my enums smarter - ie, more
in line with the rest of the language. i haven't tested it yet, but what
i came up with is a template like this:

template <typename Enum>
class smart_enum
{
public:
typedef Enum enum_type;

smart_enum() {}
smart_enum(enum_type e) e_(e) {}

enum_type get() const { return e_; }

bool operator==(smart_enum const& e) const { return e.e_ == e_; }
bool operator!=(smart_enum const& e) const { return !(e_ == *this); }

operator enum_type() const { return e_; }

private:
enum_type e_;
};

i would like this to be used to transparently replace existing enum
types - with one exception. i want to disallow:

colour c = green;

and force:

colour c = colour::green;

otherwise, i want the template to behave exactly like a regular enum
type. would this template work? or am i missing anything?

the next thing i am thinking about is making the transition to smart
enums easy, using macros. something like this:

#define DEFINE_ENUM_START(enum_t) \
namespace enum_t ## _DUMB_ENUM_ { \
typedef enum
#define DEFINE_ENUM_END(enum_t) \
enum_t; } \
typedef smart_enum< enum_t ## _DUMB_ENUM_ :: enum_t > enum_t;

again, not tested or even compiled. but what i'd like to be able to do is:

DEFINE_ENUM_START(colour)
{
red,
green,
blue
}
DEFINE_ENUM_END(colour)

has anyone seen anything like this before? are there any problems with
doing this?


How are your "smart enums" going to work in a "switch" statement?

I am still trying to understand what advantage your "enum" has over
the existing enum mechanism? What exactly do you mean by "more in
line with the rest of the language"? Could you please demonstrate
for dummies like me?

V

P.S. Sorry for the bad quoted/added ratio, just wanted to keep all
of the original post
Jul 22 '05 #2

P: n/a

Victor Bazarov wrote:
How are your "smart enums" going to work in a "switch" statement?
i don't know, that was one of those things i hadn't thought of. wouldn't
the implicit conversion operator do the trick?
I am still trying to understand what advantage your "enum" has over
the existing enum mechanism? What exactly do you mean by "more in
line with the rest of the language"? Could you please demonstrate
for dummies like me?


mostly it prevents the enum member names from being injected into the
surrounding scope. but there's a lot of functionality you could add,
such as a default value, or maybe doing some more work while comparing,
assigning, or whatever.

just off the top of my head, consider the colour enumeration:

namespace colour_ENUM_ {
typedef enum
{
red,
green,
blue
} colour;
}

template <>
class smart_enum<colour_ENUM_::colour>
{
public:
typedef Enum colour_ENUM_::colour;

smart_enum() {}
smart_enum(enum_type e) e_(e) {}

enum_type get() const { return e_; }

bool operator==(smart_enum const& e) const { return e.e_ == e_; }
bool operator!=(smart_enum const& e) const { return !(e_ == *this); }

operator enum_type() const { return e_; }

// additional stuff
string get_colour_name() const {
const char* str;

switch(e_)
{
case red: str = "red";
case green: str = "green";
case blue: str = "blue";
}

return string(str);
}

long get_html_colour() const {
switch(e_)
{
case red: return 0xFF0000L;
case green: return 0x00FF00L;
case blue: return 0x0000FFL;
}
}

private:
enum_type e_;
};

existing code that used the old colour enum should work unchanged
(except that the scope must be added to the constants), but new code
could use the new members to get the colour in a format more useful for
output.

there are probably other things too - i've been musing over this for a
couple days now, but right now i have to run. if you can hang on for
about 3 days, i can probably get back to you with more. otherwise, there
was an article that i re-read recently (which i don't have with me and
isn't online) in c/c++ user's journal - one of the ones by hyslop &
sutter. april 2004, maybe? if not, probably may. that was what got me to
thinking on these lines. there might be more in there than i can come up
with.

but a good summary is that this is about maintaining source
backwards-compatibility (and to some degree, the syntax of enums), while
elevating enum types to first-class c++ types.

mark

p.s. you know, calling yourself a dummy is a sign of poor self-esteem,
but aside from that, if you project a self-image of being a dummy,
people will hardly go out of their way to dissuade you of your opinion,
and may end up agreeing by default. i'm not really a psychiatrist, but i
just saw one on tv.

Jul 22 '05 #3

P: n/a
"Mark A. Gibbs" <x_*********@rogesr.com_x> wrote...

Victor Bazarov wrote:
How are your "smart enums" going to work in a "switch" statement?


i don't know, that was one of those things i hadn't thought of. wouldn't
the implicit conversion operator do the trick?
I am still trying to understand what advantage your "enum" has over
the existing enum mechanism? What exactly do you mean by "more in
line with the rest of the language"? Could you please demonstrate
for dummies like me?


mostly it prevents the enum member names [...]


Thank you for your explanation and your psychology (and not psychiatry)
lesson (do you know the difference? I probably don't, I only pretend
I do). However, I just wanted to point out that you may have started
with a wrong premise. Enums don't have members.

Best of luck!

Victor
Jul 22 '05 #4

P: n/a
"Mark A. Gibbs" <x_*********@rogesr.com_x> wrote in message
news:RW********************@twister01.bloor.is.net .cable.rogers.com...

[snip]


I don't have any advice to give you about how to do this, since I am just
learning the language myself. However . . .

I don't think that what you're trying to do is worth your time. My
understanding is that you are trying to design an enum that has some minor
added features over a standard enum. Basically, it's an enum that also
gives you the ability to define class functionality, such as methods and
operators.

But, as I understand it, the whole point of enums is that they aren't
classes, but just ints masked by constant names. They are supposed to be
quick and simple, with no bells and whistles. With C++, they also have
types, but those are simply to guarantee that the user knows what's going
on. AFAIK, you can still throw them around like the ints they represent,
such as:

enum Result { SUCCESS, FAILURE };

int main()
{
...
if (!error()) return SUCCESS;
else return FAILURE;
}

So my advice, which you might take, even though I'm as new to C++ as the
next guy, is to define classes if you need methods, and let enums be enums.
Jul 22 '05 #5

P: n/a
Victor Bazarov asked Mark Gibbs about his new enums:
I am still trying to understand what advantage your "enum" has over
the existing enum mechanism? What exactly do you mean by "more in
line with the rest of the language"? Could you please demonstrate
for dummies like me?

and Mark replied:
mostly it prevents the enum member names from being injected into the
surrounding scope.
Just use a namespace.
but there's a lot of functionality you could add,
such as a default value
Enums already have that.
or maybe doing some more work while comparing,
assigning, or whatever.


Seems to me, all these things can be done with existing
namespaces and enums. For example:

#include <iostream>

namespace Romulan
{
enum Ale
{
Brown = 15,
Amber = 16,
Lite = 17
};
}

int main()
{
int YourBeer;
std::cout << "Enter beer code:" << std::endl;
std::cin >> YourBeer;
switch (YourBeer)
{
case Romulan::Brown:
std::cout << "Yummy!" << std::endl;
break;
case Romulan::Amber:
std::cout << "Pretty good." << std::endl;
break;
case Romulan::Lite:
std::cout << "Eh." << std::endl;
break;
default:
std::cout << "Your beer sux, dude!" << std::endl;
break;
}
return 0;
}

All done without any "modified" enums.

--
Cheers,
Robbie Hatley
Tustin, CA, USA
email: lonewolfintj at pacbell dot net
web: home dot pacbell dot net slant earnur slant
Jul 22 '05 #6

P: n/a

Here's some code on working on at the moment:

enum EnumMonth
{
Jan = 1,
Feb = 2,
Mar = 3,
Apr = 4,
May = 5,
Jun = 6,
Jul = 7,
Aug = 8,
Sep = 9,
Oct = 10,
Nov = 11,
Dec = 12
};
class Month
{
private:

EnumMonth data;

void Set(EnumMonth month)
{
if (month < 1 || month > 12) throw bad_month();

data = month;
}

public:

class bad_month {};

explicit Month(EnumMonth month)
{
Set(month);
}

Month& operator=(Month month)
{
Set(month);
}

operator EnumMonth()
{
return data;
}
};
int main()
{
Month blah(EnumMonth(Apr));

Month blah(EnumMonth(4));

try
{
Month blah(EnumMonth(13)); //bad_month
}
catch (bad_month)
{

}

}
-JKop
Jul 22 '05 #7

P: n/a
Mark A. Gibbs wrote:

i have been toying with the idea of making my enums smarter - ie, more
in line with the rest of the language. i haven't tested it yet, but what
i came up with is a template like this:


This has been done before.
Use your favorite search engine and search for
"Dan Saks enumeration". You could also supplement
your search with "Scott Meyers enumeration"
and "Jim Hyslop enumeration". These folks have
worked out the conversion of an enumeration into
a type.

In today's world, your best effort should be spent
researching before designing. If its been done
before, either use it, tailor it, or improve it.

--
Thomas Matthews

C++ newsgroup welcome message:
http://www.slack.net/~shiva/welcome.txt
C++ Faq: http://www.parashift.com/c++-faq-lite
C Faq: http://www.eskimo.com/~scs/c-faq/top.html
alt.comp.lang.learn.c-c++ faq:
http://www.raos.demon.uk/acllc-c++/faq.html
Other sites:
http://www.josuttis.com -- C++ STL Library book

Jul 22 '05 #8

P: n/a
"Thomas Matthews" <Th****************************@sbcglobal.net> schrieb im
Newsbeitrag news:DZ**************@newssvr31.news.prodigy.com.. .
This has been done before.
Use your favorite search engine and search for
"Dan Saks enumeration". You could also supplement
your search with "Scott Meyers enumeration"
and "Jim Hyslop enumeration". These folks have
worked out the conversion of an enumeration into
a type.

I did a google on each of these but it seems that none of these addreses:
- getting a string representation of an enum value (and being able to convert
such a representation back to the enum value
- which is the first defined value in an enum
- which is the last defined value in an enum
- a typesafe operator++ which ideally (at least for some uses :-) would
respect enums with gaps:

Example for the last one:
enum E { First = 0, Second = -23, Third = 1000};

I would want to be able to do this:

for(E value = begin<E>(); value != end<E>();++value)
....

and expect the loop to iterate over the values 0,-23,1000 in that order.

(Of course you can define such an enum with macros and templates)


--
Regards,

Arne
Jul 22 '05 #9

P: n/a
Arne Adams wrote:
"Thomas Matthews" <Th****************************@sbcglobal.net> schrieb im
Newsbeitrag news:DZ**************@newssvr31.news.prodigy.com.. .
This has been done before.
Use your favorite search engine and search for
"Dan Saks enumeration". You could also supplement
your search with "Scott Meyers enumeration"
and "Jim Hyslop enumeration". These folks have
worked out the conversion of an enumeration into
a type.
I did a google on each of these but it seems that none of these addreses:
- getting a string representation of an enum value (and being able to convert
such a representation back to the enum value


This is entirely unnecessary functionality from the programming
standpoint. None of my classes have that, why should I worry
about some enums (or "smart enums")? If there is a [rare] need
to do that, it could be programmed in a separate function, on
a case-by-case basis. Besides, what if I don't want to enter
"red" for colour::red, but "rouge" or "красное"?

I guess, if you need to have a special _type_ like other folks
have done, you can always derive from their type and extend their
functionality to accommodate serialising, can't you?
- which is the first defined value in an enum
How is that relevant for programming, really? Enums are just
named constants. They usually don't have any order defined for
them. They are also not dependent.
- which is the last defined value in an enum
Same question of relevancy.
- a typesafe operator++ which ideally (at least for some uses :-) would
respect enums with gaps:

Example for the last one:
enum E { First = 0, Second = -23, Third = 1000};

I would want to be able to do this:

for(E value = begin<E>(); value != end<E>();++value)
...

and expect the loop to iterate over the values 0,-23,1000 in that order.


Why? IIRC, in my more than 10 years of programming C++ I've _never_
had a need in ++ operator for enums, nor for "begin" and "end". If
you feel you need that functionality, then why not have a standard
list<int> with fixed values or even a simple array?

I think you're trying to create your own, user-defined, type with
some functionality that enum has never been known to have. Why do
you want to tie it up with the term enum or make them related in some
way? Wouldn't it be better to just say that you're creating a different
type altogether?

V
Jul 22 '05 #10

P: n/a
"Victor Bazarov" <v.********@comAcast.net> schrieb im Newsbeitrag
news:qM*****************@ord-read.news.verio.net...
- getting a string representation of an enum value (and being able to convert such a representation back to the enum value


This is entirely unnecessary functionality from the programming
standpoint.

enums are a bit more than named constants.
For instance they facilitate debugging because (at least most debuggers I have
used) display the symbolic name of the enum value at hand.
Hence
enum Color
{red,blue,yellow};

is different from
namespace Color
{
const int red = 1;
const int blue = 2;
const int yellow = 3;
}

If you need to make these constants persistent some may find it useful to save
the symbolic names.

Apart from that each enum is a different type, it can be used for static
overloading and mismatchs are detected at compiletime.
Example for the last one:
enum E { First = 0, Second = -23, Third = 1000};

I would want to be able to do this:

for(E value = begin<E>(); value != end<E>();++value)
...

and expect the loop to iterate over the values 0,-23,1000 in that order.


Why? IIRC, in my more than 10 years of programming C++ I've _never_
had a need in ++ operator for enums, nor for "begin" and "end". If
you feel you need that functionality, then why not have a standard
list<int> with fixed values or even a simple array?


If I use enums to encode variations of a problem domain (for the typesafety, for
ease of debugging, for whatever reason) then it can be useful to be able to loop
over all values.

But of course it is possible that I am the only C++ programmer who needs this
sometimes.

--
Regards,

Arne
Jul 22 '05 #11

P: n/a
Arne Adams wrote:

If I use enums to encode variations of a problem domain (for the typesafety, for
ease of debugging, for whatever reason) then it can be useful to be able to loop
over all values.

But of course it is possible that I am the only C++ programmer who needs this
sometimes.


Perhaps there is some blend between enum constants and enum ranges.
In Pascal, one can define a range of constants. Which is a shorthand
notation for a set of constants.

Are enums a set or just "random" constants with names. Let us discuss
this.

The enum facility allows declaring of values to named constants. The
compiler generates the values if the values are not specified. There
is no mandate that the values or names be related:
enum Fried_Tomato {Green, Chocolate, Torque, Velocity};
enum Punkin {Red = 400, Blue = 25, Speed = 66, Linguicity = 75};
The compiler is assigning names to constants and associating them
with a type.

However, this does parallel set notation. Not knowing the
specifics of enum, one expects that the identifiers are in a
set with the given tag identifier. If one views this as a
set, one expects to use set operations on the values,
especially iteration. But they are not a set, as one cannot
insert into the set. Maybe a constant set? Nope, as a
set implies unique values to the names.

More confusion: One can declare a variable of the enumeration
type and perform integral operations on that variable.
Given:
Fried_Tomato automobile(Torque);
One could issue this statement:
cout << automobile << '\n';
and have the value of 3 printed out.
Taking this one more step:
automobile += 7;
cout << automobile << '\n';
will print out the value of 10.
Hmmm, enums are not just constants or are they?

The enum type identifier when used to declare a object
will declare an integer value. So the statement:
Punkin james;
is the same as
int james;
This explains the above behavior of automobile.

The above behavior also shows that an enum is not a set.
One cannot increment a set nor perform addition with the
set, as the set is not one value but a collection. Addition
of an integer with a set is not defined in C++. Perhaps
in the relm of mathematics (such as scalar addition with
a vector).

One can use a named constant from an enum as the constant
in a 'case' statement or as the size of an array. A member
of a set cannot be used this way.

Both set and enum do not provide facilities for converting
from the value to the named constant. Many people have
wanted this functionality (I know that it really helps
in debugging).

Let us extend this confusion by comparing an enum to a
range. First a definition of a range {mine}:
A range is a contiguous, sequence of integers
from a beginning value to an ending value, inclusive,
within the capacity of the int type.
So many programmers often use the enum to represent a
range of values:
enum Weekday {Sunday, Monday, Tuesday, Wednesday,
Thursday, Friday, Saturday};
The range is Sunday .. Saturday; values 0 .. 7. The
range, because it is contiguous, allows incrementing
and decrementing. However, extending beyond the
beginning or end is undefined. Thus one could have
these statements:
Weekday today(Sunday);
Weekday tomorrow;
tomorrow = today + 1;
if (tomorrow == Monday)
{
// This code would always be executed.
}
Enums, as shown above, exhibit the same behavior.
"But you said that the enum values don't have to be

related."

Yes, this is where many programs crash. I could make
one subtle change:
enum Weekday {Sunday, Monday = 15, Tuesday, Wednesday,
Thursday, Friday, Saturday};
and the above code blows up. This demonstrates that
an enum is not a range.
So a programmer must decide exactly what is needed: either
named constants not necessarily related, or a set, or
a range. For sets and ranges, one should use a class.
As for using enum versus #defines or const, I'll leave
that up to this group for discussion. I know that #define
does not have scoping. "const" variables inside a class
definition, cannot be used to specify the size of an array
and also need to be initialized somewhere; whereas an
enum inside a class can be used to specify the size of
an array.

Now that I've examined the enum more closely, I will
not use it for implied sets or ranges.

--
Thomas Matthews

C++ newsgroup welcome message:
http://www.slack.net/~shiva/welcome.txt
C++ Faq: http://www.parashift.com/c++-faq-lite
C Faq: http://www.eskimo.com/~scs/c-faq/top.html
alt.comp.lang.learn.c-c++ faq:
http://www.raos.demon.uk/acllc-c++/faq.html
Other sites:
http://www.josuttis.com -- C++ STL Library book

Jul 22 '05 #12

P: n/a
"Thomas Matthews" <Th****************************@sbcglobal.net> schrieb im
Newsbeitrag news:pT***************@newssvr31.news.prodigy.com. ..
Given:
Fried_Tomato automobile(Torque);
One could issue this statement:
cout << automobile << '\n';
and have the value of 3 printed out.
Taking this one more step:
automobile += 7; This won't compile on a conforming compiler: an integer is not implicitly
convertible to an enum.
Punkin james;
is the same as
int james; no - see above.

This explains the above behavior of automobile.

The above behavior also shows that an enum is not a set. At least when you do not need different names for the same value, an enum is a
typed constant finite set of values.

Let us extend this confusion by comparing an enum to a
range. First a definition of a range {mine}:
A range is a contiguous, sequence of integers
from a beginning value to an ending value, inclusive,
within the capacity of the int type. So many programmers often use the enum to represent a
range of values:
enum Weekday {Sunday, Monday, Tuesday, Wednesday,
Thursday, Friday, Saturday};
The range is Sunday .. Saturday; values 0 .. 7.
but here the values are completely irrelevant as long as they preserve the order
implied by the definition of the enum.
A loop that has to do something foreach weekday could look like
for(Weekday day = Sunday; day <= Saturday; ++day)
// ++day won't compile with current enums.
If the programmer had to provide values for the enumerated constants (for
bitmasks or whatever) I would still like the above loop to work or better the
variation where I do not need to know that Sunday is the first and Saturday the
last weekday (could as well let the week start with Monday and end with Sunday):
for(Weekday day = begin<Weekday>(); day <= end<Weekday>(); ++day)

The weekday enum would be considered contiguous regardless of the difference
between consecutive values in that enum.
(provided, of course that all weekdays are present and no more than these).
Yes, this is where many programs crash. I could make
one subtle change:
enum Weekday {Sunday, Monday = 15, Tuesday, Wednesday,
Thursday, Friday, Saturday};
and the above code blows up. This demonstrates that
an enum is not a range. Yes again that is why I prefer the iteration proposed above.
So a programmer must decide exactly what is needed: either
named constants not necessarily related, or a set, or
a range.

or a lightweight typed constant set like an enum is.
--
Regards,

Arne
Jul 22 '05 #13

P: n/a
Is there any chance your enums are going to print their name
instead of value when I output them ? I mean

#include <iostream>
using namespace std;

enum color
{
red,
green,
blue,
};

int main()
{
color cl = green;
cout << cl; // prints green instead of 1 ?
}

That is the only thing I miss about enums - I have to write
a separate function for each enum if I ever want to output
the string literal for the enum.
Which brings me to a question - Is it possible to overload
a function based on enum ?

-Arijit
Jul 22 '05 #14

P: n/a
Arijit wrote:
Is there any chance your enums are going to print their name
instead of value when I output them ? I mean

#include <iostream>
using namespace std;

enum color
{
red,
green,
blue,
};

int main()
{
color cl = green;
cout << cl; // prints green instead of 1 ?
}


Try this:

#include <iostream>

using namespace std;

enum Color
{
red, green, blue
};

ostream& operator<<(ostream& out, Color color)
{
switch(color)
{
case red: out << "Red";
break;
case green: out << "Green";
break;
case blue: out << "Blue";
break;
default: out << "Huh???";
break;
}

return out;
}
int main()
{
Color color = blue;
cout << color << endl;
return 0;
}

--
Peter van Merkerk
peter.van.merkerk(at)dse.nl
Jul 22 '05 #15

P: n/a
Peter van Merkerk <me*****@deadspam.com> wrote in message news:<2l************@uni-berlin.de>...
Try this:

#include <iostream>

using namespace std;

enum Color
{
red, green, blue
};

ostream& operator<<(ostream& out, Color color)
{
switch(color)
{
case red: out << "Red";
break;
case green: out << "Green";
break;
case blue: out << "Blue";
break;
default: out << "Huh???";
break;
}

return out;
}
int main()
{
Color color = blue;
cout << color << endl;
return 0;
}


Thanks for the example, but I still have to write the
switch statement. I specifically want to avoid that.
My main gripe is - the the symbolic names for my enum constants are
already in the program - why do I have to write them twice ?
But I guess thats not possible without using macros, and we all
know better than to use them.

-Arijit
Jul 22 '05 #16

P: n/a
Arijit wrote:
Peter van Merkerk <me*****@deadspam.com> wrote in message news:<2l************@uni-berlin.de>...

Try this:

#include <iostream>

using namespace std;

enum Color
{
red, green, blue
};

ostream& operator<<(ostream& out, Color color)
{
switch(color)
{
case red: out << "Red";
break;
case green: out << "Green";
break;
case blue: out << "Blue";
break;
default: out << "Huh???";
break;
}

return out;
}
int main()
{
Color color = blue;
cout << color << endl;
return 0;
}

Thanks for the example, but I still have to write the
switch statement. I specifically want to avoid that.
My main gripe is - the the symbolic names for my enum constants are
already in the program - why do I have to write them twice ?
But I guess thats not possible without using macros, and we all
know better than to use them.


Over the years I have rarely had the need to literally output the names
of symbolic enum constants. Usually there isn't an exact match between
the internal enumerator identifiers and the string representation I
would like to see. Actually I prefer to keep the things that are to
presented to the user separate from the rest of my code. The only cases
in which automatic enum to string conversion would be useful for me is
in debug logs.

Of course YMMV, and if you really think it would be a big time saver you
could make a code generator that generates something like the function
above based on an enum definition. Integrate the code generator into
your make file and you don't have to worry about it again.

--
Peter van Merkerk
peter.van.merkerk(at)dse.nl
Jul 22 '05 #17

P: n/a
Arijit wrote:
[...]
My main gripe is - the the symbolic names for my enum constants are
already in the program - why do I have to write them twice ?
But I guess thats not possible without using macros, and we all
know better than to use them.


Have you ever considered that there are plenty of "symbolic
names" around in the program that are NEVER available for UI
_unless_ you "write them twice"? Class names, variable names,
function names, and so on...
Jul 22 '05 #18

P: n/a
Victor Bazarov wrote:
Arijit wrote:
[...]
My main gripe is - the the symbolic names for my enum constants are
already in the program - why do I have to write them twice ?
But I guess thats not possible without using macros, and we all
know better than to use them.

Have you ever considered that there are plenty of "symbolic
names" around in the program that are NEVER available for UI
_unless_ you "write them twice"? Class names, variable names,
function names, and so on...


Actually class names are usually available as string via the typeid()
operator. Unfortunately the standard does not specify how that string
should look like; a complying but not very useful implementation could
return just empty strings. So it is really only useful as a debugging aid.

--
Peter van Merkerk
peter.van.merkerk(at)dse.nl
Jul 22 '05 #19

P: n/a
Peter van Merkerk wrote:
Victor Bazarov wrote:
Arijit wrote:
[...]
My main gripe is - the the symbolic names for my enum constants are
already in the program - why do I have to write them twice ?
But I guess thats not possible without using macros, and we all
know better than to use them.


Have you ever considered that there are plenty of "symbolic
names" around in the program that are NEVER available for UI
_unless_ you "write them twice"? Class names, variable names,
function names, and so on...

Actually class names are usually available as string via the typeid()
operator. Unfortunately the standard does not specify how that string
should look like; a complying but not very useful implementation could
return just empty strings. So it is really only useful as a debugging aid.


Well, _usually_ doesn't really cut it, does it? No guarantees only
guarantees absence. Function names are also often available but not
in the form I'd like (I mean that they exist in the OBJ files and in
the shared objects, or DLLs as they are often called, and I _could_
extract them if I wanted to)...
Jul 22 '05 #20

P: n/a
Victor Bazarov wrote:
Peter van Merkerk wrote:
Victor Bazarov wrote:
Arijit wrote:

[...]
My main gripe is - the the symbolic names for my enum constants are
already in the program - why do I have to write them twice ?
But I guess thats not possible without using macros, and we all
know better than to use them.

Have you ever considered that there are plenty of "symbolic
names" around in the program that are NEVER available for UI
_unless_ you "write them twice"? Class names, variable names,
function names, and so on...
Actually class names are usually available as string via the typeid()
operator. Unfortunately the standard does not specify how that string
should look like; a complying but not very useful implementation could
return just empty strings. So it is really only useful as a debugging
aid.


Well, _usually_ doesn't really cut it, does it?


I don't know why Arijit wants this, so I leave up Arijit to answer this
question.
No guarantees only guarantees absence.
If there are no guarantees, absense is not guaranteed.
Function names are also often available but not
in the form I'd like (I mean that they exist in the OBJ files and in
the shared objects, or DLLs as they are often called, and I _could_
extract them if I wanted to)...


Like I said before other than for debugging purposes I have little or no
need to output identifier names no matter what form they are.

--
Peter van Merkerk
peter.van.merkerk(at)dse.nl
Jul 22 '05 #21

P: n/a
pa*****@yahoo.co.in (Arijit) wrote:
My main gripe is - the the symbolic names for my enum constants are
already in the program - why do I have to write them twice ?


/* File e.cc */
#include <iostream>
#include "en.h"
#define WHATEVER
#include "en.h"

int main()
{
std::cout << Red << " = " << (int)Red << '\n';
}
/* File en.h */
#define OP_DEC std::ostream &operator<<(std::ostream &os, Colours c)

#ifdef WHATEVER
#define E(x) case x: ch = #x; break;
#define EE(x, n) E(x)
OP_DEC
{
char const *ch;
switch(c) {
#else
#define E(x) x,
#define EE(x, n) x = n,
;
enum Colours {
#endif

E(Green)
EE(Red, 3)
E(Blue)
E(Yellow)

#ifdef WHATEVER
default: return os << "Unknown colour " << (int)c;
}
return os << ch;
}
#else
};
OP_DEC;
#endif

#undef E
#undef EE
#undef OP_DEC
Jul 22 '05 #22

P: n/a
Victor Bazarov <v.********@comAcast.net> wrote in message news:<oZ*****************@ord-read.news.verio.net>...
Arijit wrote:
[...]
My main gripe is - the the symbolic names for my enum constants are
already in the program - why do I have to write them twice ?
But I guess thats not possible without using macros, and we all
know better than to use them.


Have you ever considered that there are plenty of "symbolic
names" around in the program that are NEVER available for UI
_unless_ you "write them twice"? Class names, variable names,
function names, and so on...


You never need to output the names of your functions or classes
to the user, except, as Peter pointed out, for debugging. And even
in that case its seldom necessary if you have access to a debugger.
But it is quite possible that one might want to print the enum
name directly. For example:

#include <iostream>

using namespace std;

class Box
{
int height;
int width;
int length;

public:
enum color
{ red,green,blue }
clr;

Box(int h,int w,int l,color c):height(h),
width(w),length(l),clr(c)
{}

friend ostream& operator<<(ostream& ostr, Box b)
{
ostr << "Height:" << b.height << endl
<< "Width:" << b.width << endl
<< "Length:" << b.length << endl
<< "Color:" << b.clr << endl;
return ostr;
}
};

int main()
{
Box B(10,20,30,Box::red);
cout << B;

return 0;
}

The simple enum name would suffice in this case.

Writing a function separately is a trivial job, but its quite
monotonous for a large enum with 30-40 or even more elements.

Note that I am not saying that this feature is very useful or
that its absence is a major problem, but it would be nice
to have it. Its like using a calculator to multiply 254 and 382.
Sure I can do it, but the calculator will spare me a little trouble.

-Arijit
Jul 22 '05 #23

P: n/a

i got a lot of replies during my hiatus, but unfortunately, none of them
seem to be thinking the same way as me with regards to what a smarter
enum type would be like.

Victor Bazarov wrote:
mostly it prevents the enum member names [...]

Thank you for your explanation and your psychology (and not psychiatry)
lesson (do you know the difference? I probably don't, I only pretend
I do). However, I just wanted to point out that you may have started
with a wrong premise. Enums don't have members.


semantics. whatever you want to call them, i was clearly referring to
the constituent entities of an enumeration.

btw, you were incorrect, psychiatry was the correct term for what i was
doing. and yes, i am quite familiar with the difference. this may aid
you the next time you get confused: if a man says to a psychiatrist, "i
want to kill everyone i know", the psychiatrist will ask him to tell him
more, and in the course of their conversation help the man understand
why he feels so much anger, and help him work it out non-agressively.

if the same man were to say the same thing to a psychologist, the
psychologist would say, "wow, thanks for telling me that", and note it
in his journal.

Aguilar, James wrote: I don't think that what you're trying to do is worth your time. My
understanding is that you are trying to design an enum that has some minor added features over a standard enum. Basically, it's an enum that also
gives you the ability to define class functionality, such as methods and
operators.
no, that is incorrect, but that is my fault. i was more concerned with
musing out a potential starting point for a solution than explaining
what i was after. one of the things i am really hoping to prevent is this:

typedef enum { a, b, c } A;
typedef enum { x, y, z } Z;

A foo = a;
Z bar = x;

a == x; // will test true, though it is obviously not

and this:

// foo.hpp
typedef enum { a, b, c } foo_enum;
// changed to typedef enum { a, e, i } foo_enum;

// bar.hpp
typedef enum { d, e, f } bar_enum;
// changed to typedef enum { b, c, d } bar_enum;

// file.cpp
#include "foo.hpp"
#include "bar.hpp"
void func(foo_enum foo)
{
// will break silently with the changes
switch (foo)
{
case c: // it's a c
case b: // it's a b
default: // must be an a
}
}

i am not particularly interested in adding iteration to my enumerations,
and while printing the symbolic names of my enumerations would be nice,
it's not really necessary. really, i'm not interested in adding any
functionality at all - all i'm after is stricter type- and name-safety.
and even then, only in debug compile mode if i have to.

incidently, i had another look at that magazine, and the big trick was:

typedef enum { a, b = 1234, c = 0xFFFFFFFFU } enum_type;

cout << c;
cout << (b > c);

Thomas Matthews wrote: This has been done before.
Use your favorite search engine and search for
"Dan Saks enumeration". You could also supplement
your search with "Scott Meyers enumeration"
and "Jim Hyslop enumeration". These folks have
worked out the conversion of an enumeration into
a type.

In today's world, your best effort should be spent
researching before designing. If its been done
before, either use it, tailor it, or improve it.


i really hate pointing out the obvious, but if i were going to go do it
all on my own, why would i be here *specifically* asking if anyone has
seen it done before?

as for the links, they may be exactly what i was looking for, but i
couldn't find anything relevant under hyslop or meyers (too much other
crap came up), and saks seemed more concerened with adding iteration to
enumerations, which i am not interested in. does anyone have more
specific information i could use to search? i suspect that hyslop has
dealt with what i'm after (based on his other work), but maybe meyers
has, too.

mark
Jul 22 '05 #24

P: n/a
Mark A. Gibbs wrote:
i got a lot of replies during my hiatus, but unfortunately, none of them
seem to be thinking the same way as me with regards to what a smarter
enum type would be like.

Victor Bazarov wrote:
mostly it prevents the enum member names [...]
Thank you for your explanation and your psychology (and not psychiatry)
lesson (do you know the difference? I probably don't, I only pretend
I do). However, I just wanted to point out that you may have started
with a wrong premise. Enums don't have members.

semantics. whatever you want to call them, i was clearly referring to
the constituent entities of an enumeration.


They are not entities of an enumeration, and that's the whole point.
Each _enumerator_ (yes, that's what they are called) exist in the
same scope as the enumeration they are declared in. It has its own
type, yes. The same type as the other enumerators declared in the
same enum declaration. The difference between enum declarations is
designated by the _name_ of the enumeration.

btw, you were incorrect, psychiatry was the correct term for what i was
doing. and yes, i am quite familiar with the difference. this may aid
you the next time you get confused: if a man says to a psychiatrist, "i
want to kill everyone i know", the psychiatrist will ask him to tell him
more, and in the course of their conversation help the man understand
why he feels so much anger, and help him work it out non-agressively.

if the same man were to say the same thing to a psychologist, the
psychologist would say, "wow, thanks for telling me that", and note it
in his journal.
Nope. The difference is in what they treat and how they treat it.
By mentioning a psychiatrist you implied that low self-esteem is
a mental disease or disorder. By correcting you I implied that low
self-esteem is nothing more than a character trait. Diseases and
disorders are treated by psychiatrists, and treated with medication,
while psychologists help people understand and change character traits.

In most cases psychiatrists are also psychologists, i.e. they can talk
people into or out of something, but the inverse is not true, no
psychologist has a right to prescribe any drugs (unless he/she is also
a medical doctor).
[...] i was more concerned with
musing out a potential starting point for a solution than explaining
what i was after. one of the things i am really hoping to prevent is this:

typedef enum { a, b, c } A;
typedef enum { x, y, z } Z;

A foo = a;
Z bar = x;

a == x; // will test true, though it is obviously not
Why is it not? Both are declared right after the curly brace without
a special initialiser. Both are declared inside an enumeration with
the same name (no name is a unique name). Why shouldn't they compare
equal?

BTW, 'A' and 'Z' here are just two synonyms for the same type.

and this:

// foo.hpp
typedef enum { a, b, c } foo_enum;
// changed to typedef enum { a, e, i } foo_enum;

// bar.hpp
typedef enum { d, e, f } bar_enum;
// changed to typedef enum { b, c, d } bar_enum;
Again, 'foo_enum' and 'bar_enum' are but the same type, only two
different names for it. Drop the 'typedef' nonsense.

// file.cpp
#include "foo.hpp"
#include "bar.hpp"
void func(foo_enum foo)
{
// will break silently with the changes
And you propose that it should say what?
switch (foo)
{
case c: // it's a c
case b: // it's a b
default: // must be an a
}
}
[...]


Perhaps what you're trying to get to is this:

enum ABC { a,b,c };
enum XYZ { x,y,z };

int main()
{
ABC abc = a;
XYZ xyz = y;
return abc == xyz;
}

'abc' and 'xyz' should not just compare non-equal, but an attempt to
compare them should not compile since they are of two different types.

That's not [yet] how the language works. The comparison causes both
values to be promoted to ints. Perhaps they shouldn't, but that's
how it is, and to change that, go to comp.std.c++ and make your case.

BTW, you cannot assign 'xyz' to 'abc', they are of different types.
You can convert between them, though, a static_cast<> is enough.

Introducing a separate type to handle those things the way _you_ want
them handled is just fine. Call them "smart enums", I have no problem
with that. I am still not sure what you mean by "more in line with
the rest of the language", though. Prevention from inserting them
into the surrounding scope is definitely _not_ an improvement. Besides,
how many people have relied on the enumerators being in the scope? I
have no idea, but I'd guess, millions.

Try posting to (and talking to smart people in) comp.std.c++. See what
they say. That's "the rest of the language" crowd. They know more, and
they will pick up on what you are proposing quicker.

Victor
Jul 22 '05 #25

P: n/a

Victor Bazarov wrote:
They are not entities of an enumeration, and that's the whole point.
Each _enumerator_ (yes, that's what they are called) exist in the
same scope as the enumeration they are declared in. It has its own
type, yes. The same type as the other enumerators declared in the
same enum declaration. The difference between enum declarations is
designated by the _name_ of the enumeration.
ah, that i didn't realize. that is good to know.
Nope. The difference is in what they treat and how they treat it.
By mentioning a psychiatrist you implied that low self-esteem is
a mental disease or disorder. By correcting you I implied that low
self-esteem is nothing more than a character trait. Diseases and
that was really the point of the joke, that low self-esteem is a DSM4
disorder that should be treated. but i guess it doesn't matter now.
and this:

// foo.hpp
typedef enum { a, b, c } foo_enum;
// changed to typedef enum { a, e, i } foo_enum;

// bar.hpp
typedef enum { d, e, f } bar_enum;
// changed to typedef enum { b, c, d } bar_enum;

Again, 'foo_enum' and 'bar_enum' are but the same type, only two
different names for it. Drop the 'typedef' nonsense.

// file.cpp
#include "foo.hpp"
#include "bar.hpp"
void func(foo_enum foo)
{
// will break silently with the changes

And you propose that it should say what?


i don't know, "comparing values of two different types" maybe? (i
realize now that they *are* the same type in the code as i wrote, but
assume that i had declared them properly as different types - the
problem still exists).
switch (foo)
{
case c: // it's a c
case b: // it's a b
default: // must be an a
}
}
[...]

Perhaps what you're trying to get to is this:

enum ABC { a,b,c };
enum XYZ { x,y,z };

int main()
{
ABC abc = a;
XYZ xyz = y;
return abc == xyz;
}

'abc' and 'xyz' should not just compare non-equal, but an attempt to
compare them should not compile since they are of two different types.


and that is one of the things i am trying to accomplish.
That's not [yet] how the language works. The comparison causes both
values to be promoted to ints. Perhaps they shouldn't, but that's
how it is, and to change that, go to comp.std.c++ and make your case.
no no no, i have no interest in changing the language. leave enums be.
what i asked for was a way to create something enum-like with certain
differences (that i referred to as improvements, but of course, you're
free to debate), using the current language. that is definitely the
domain of this group.
BTW, you cannot assign 'xyz' to 'abc', they are of different types.
You can convert between them, though, a static_cast<> is enough.
yes, and that much is good.
Introducing a separate type to handle those things the way _you_ want
them handled is just fine. Call them "smart enums", I have no problem
with that. I am still not sure what you mean by "more in line with
the rest of the language", though. Prevention from inserting them
into the surrounding scope is definitely _not_ an improvement. Besides,
how many people have relied on the enumerators being in the scope? I
have no idea, but I'd guess, millions.
the reason i said more in line with the rest of the language is because
the enum syntax makes a curious departure from the norm. as far as i
know, enum is the only c++ construct that allows you to declare a symbol
within braces, and have that symbol accessible in the surrounding scope,
without qualification. am i wrong?

i don't particularly care how many programmers rely on enumerators being
injected into the surrounding scope - that is not really relevant to
creating a something new, now is it? unless you are suggesting that
there is a good reason to insert enumerators into the surrounding scope,
besides backwards compatibility (which i would consider, but only after
everything else works). if there is, i would like to know it before i do
anything else.
Try posting to (and talking to smart people in) comp.std.c++. See what
they say. That's "the rest of the language" crowd. They know more, and
they will pick up on what you are proposing quicker.


as i mentioned above, i don't want to change the standard. i don't want
to improve enums, i want to make something that is an improved enum.
there are worlds of difference, and they ain't just semantic.

let me try again to specify what i'm trying to do. i am trying to create
some kind of analogue to enum. it would let me define typed symbolic
constants. the only differences between enum and what i would like are:
1.) the option of having no implicit conversion to int
2.) the ability to specify the type of the enumeration
3.) a new scope created for enumerators

and that's all. everything else (iteration, printing symbolic names,
etc.) can come later. you saw my initial attempt to do this with
templates and macros. i had hoped that someone out there has done
something similar already, but if not, i would appreciate some advice on
what i have done so far.

for the record, i have considered static constants already, but a
"static const int" is not the same as an integer constant.

if this is really a complete waste of time, i would like to hear some
arguments as to why. personally, i think this would be a very useful
addition to my programming playbook, especially if there was a simple
way to convert existing enums to the new format.

mark

Jul 22 '05 #26

P: n/a
Hi try reading

Strongly Typed Enums by H. Sutter, D. Miller

http://std.dkuug.dk/jtc1/sc22/wg21/d...2004/n1579.pdf

"Mark A. Gibbs" <x_*********@rogers.com_x> wrote in message
news:Eg********************@twister01.bloor.is.net .cable.rogers.com...

i got a lot of replies during my hiatus, but unfortunately, none of them
seem to be thinking the same way as me with regards to what a smarter
enum type would be like.

Victor Bazarov wrote:
mostly it prevents the enum member names [...]

Thank you for your explanation and your psychology (and not psychiatry)
lesson (do you know the difference? I probably don't, I only pretend
I do). However, I just wanted to point out that you may have started
with a wrong premise. Enums don't have members.


semantics. whatever you want to call them, i was clearly referring to
the constituent entities of an enumeration.

btw, you were incorrect, psychiatry was the correct term for what i was
doing. and yes, i am quite familiar with the difference. this may aid
you the next time you get confused: if a man says to a psychiatrist, "i
want to kill everyone i know", the psychiatrist will ask him to tell him
more, and in the course of their conversation help the man understand
why he feels so much anger, and help him work it out non-agressively.

if the same man were to say the same thing to a psychologist, the
psychologist would say, "wow, thanks for telling me that", and note it
in his journal.

Aguilar, James wrote:
I don't think that what you're trying to do is worth your time. My
understanding is that you are trying to design an enum that has some

minor
added features over a standard enum. Basically, it's an enum that also
gives you the ability to define class functionality, such as methods and
operators.


no, that is incorrect, but that is my fault. i was more concerned with
musing out a potential starting point for a solution than explaining
what i was after. one of the things i am really hoping to prevent is this:

typedef enum { a, b, c } A;
typedef enum { x, y, z } Z;

A foo = a;
Z bar = x;

a == x; // will test true, though it is obviously not

and this:

// foo.hpp
typedef enum { a, b, c } foo_enum;
// changed to typedef enum { a, e, i } foo_enum;

// bar.hpp
typedef enum { d, e, f } bar_enum;
// changed to typedef enum { b, c, d } bar_enum;

// file.cpp
#include "foo.hpp"
#include "bar.hpp"
void func(foo_enum foo)
{
// will break silently with the changes
switch (foo)
{
case c: // it's a c
case b: // it's a b
default: // must be an a
}
}

i am not particularly interested in adding iteration to my enumerations,
and while printing the symbolic names of my enumerations would be nice,
it's not really necessary. really, i'm not interested in adding any
functionality at all - all i'm after is stricter type- and name-safety.
and even then, only in debug compile mode if i have to.

incidently, i had another look at that magazine, and the big trick was:

typedef enum { a, b = 1234, c = 0xFFFFFFFFU } enum_type;

cout << c;
cout << (b > c);

Thomas Matthews wrote:
This has been done before.
Use your favorite search engine and search for
"Dan Saks enumeration". You could also supplement
your search with "Scott Meyers enumeration"
and "Jim Hyslop enumeration". These folks have
worked out the conversion of an enumeration into
a type.

In today's world, your best effort should be spent
researching before designing. If its been done
before, either use it, tailor it, or improve it.


i really hate pointing out the obvious, but if i were going to go do it
all on my own, why would i be here *specifically* asking if anyone has
seen it done before?

as for the links, they may be exactly what i was looking for, but i
couldn't find anything relevant under hyslop or meyers (too much other
crap came up), and saks seemed more concerened with adding iteration to
enumerations, which i am not interested in. does anyone have more
specific information i could use to search? i suspect that hyslop has
dealt with what i'm after (based on his other work), but maybe meyers
has, too.

mark

Jul 22 '05 #27

P: n/a

Michael D. Borghardt wrote:
Hi try reading

Strongly Typed Enums by H. Sutter, D. Miller

http://std.dkuug.dk/jtc1/sc22/wg21/d...2004/n1579.pdf


thank you for the reference. i was aware that something along these
lines was being discussed for standardization, though i have no idea
where it's at. is it likely to be included in any form? looks like it
was planned to be discussed in sydney, but i really don't understand the
whole process *that* well.

so it looks like the only practical way to implement the facilities
discussed in that paper is by use of a method similar to:

class colour
{
public:
enum colour_ { red_, green_, blue_ };

// one for each enumerator
static const colour red;
static const colour green;
static const colour blue;

colour(colour_ c) c_(c) {}

// operator==, member to_int(), etc.

private:
colour_ c_;
};

colour colour::red(colour::red_);
// etc.

i suppose that will have to do for now. thank you for your help everyone.

mark

Jul 22 '05 #28

This discussion thread is closed

Replies have been disabled for this discussion.