[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]
[ about comp.lang.c++.moderated. First time posters: do this! ]
Do you mean if the not all values in the range have enumerators? Yes
because the Standard requires that all the integer values between the
lowest and highest (actually more than that) are valid values of the
enum.
Francis Glassborow Journal Editor, Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
Sure, it requires a big switch statement (or something semantically
equal) to return the respective next enum value.
enum E {a, b=5, c=9};
E& operator++(E& e)
{
switch(e) {
case a: e=b; break;
case b: e=c; break;
case c: throw(....);
default: throw(....);
return e;
}
--
Ronald Fischer <rona...@my-deja.com>
http://ourworld.compuserve.com/homepages/ronald_fischer/
Sent via Deja.com http://www.deja.com/
Share what you know. Learn what you don't.
That all depends on the intent of ++. If you mean the value of the next
enumeration constant you will have a problem with:
enum X {a, b=5, c=9, d=5};
If every enumeration constant is unique then use a map to map each to
the next (and presumably the last to the first).
Francis Glassborow Journal Editor, Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]
It's legal to do:
if (e == c)
return (a);
else
return (E)((int)e + 1));
Paul
Ooops! Of course, only if the enum values are consecutive.
And once you've done that, remember to define operator+ and operator- as
well; or you might run into hard to find bugs based on the fact that
++e;
and
e = E(e+1);
produce very different results.
An even better way of avoiding this kind of bugs is to not write a
non-contiguous operator++ in the first place!
- Anders
But that's not equivalent.
There are three differences:
- The original code considers only a, b, c as legal values of E,
while your code considers everything between a and c as such
(that is, also values like E(2) or E(7)).
- The original code has a linear model, while yours is circular
(i.e., after c, you go back to a, while in the original,
incrementing from c was illegal).
- The original code tests for illegal values, yours doesn't.
In certain cases, the following might make sense as well:
enum E { a=1, b=2, c=4, d=8, e=16, f=32, finish=64 };
E& operator++(E& x)
{
return x=E(x<<1);
}
Then you can do loops like this:
for (E flag=a; flag<finish; ++flag)
std::cout << (flagset & flag)? flagletter(flag) : '-';
--
Martin Fabian http://www.s2.chalmers.se/~fabian/
--
"Cheer up. It may never happen" (Edina Monsoon)
/* Remove NOSPAM from reply-to address to mail me */
I would not consider this a disadvantage. After all, for any enum E, an
expression of shape
E(anything_may_be_here)
signals to the reader that an illegal code might be produced, so while
it might make sense to redefine operator+, it is not for the reason that
E(e+1) would do "surprising" things, but for the reason you would want
your clients to allow writing expressions like
E e1, e2;
e1 = e1 + 1;
Ronald
--
Ronald Fischer <rona...@my-deja.com>
http://ourworld.compuserve.com/homepages/ronald_fischer/
Sent via Deja.com http://www.deja.com/
Share what you know. Learn what you don't.
[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]
Do please tell us how you distinguish between the following:
X x(b), y(d);
++x;
++y;
so that x gets the value 9 and y gets the value 0. Because AFAIK
b == d;
is required to be true.
Francis Glassborow Journal Editor, Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]
Fine. So how do you determine if the current value of the enum is b or
d, in order to generate the correct following value.
--
James Kanze mailto: James...@dresdner-bank.com
Conseils en informatique orientée objet/
Beratung in objekt orientierter Datenverarbeitung
Ziegelhüttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627
Sent via Deja.com http://www.deja.com/
Share what you know. Learn what you don't.
[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]
> Ooops! Of course, only if the enum values are consecutive.
It is "legal" anyway, because an enumerated type must be able to hold
(basically) at least as many bits as required by the value of the highest
enumerator. However, it doesn't necessarily yeild any meaningful values
for the client.
---
Vesa Karvonen
>[...]
>> ++e;
>> and
>> e = E(e+1);
>> produce very different results.
>
>I would not consider this a disadvantage. After all, for any enum E, an
>expression of shape
>
> E(anything_may_be_here)
>
>signals to the reader that an illegal code might be produced
[...]
The semantics is that of an old-style cast, but the syntax is that of a
plain, inconspicuous object construction. Doesn't signal a thing.
Conversions from int to enum are bound to be common with non-contiguous
enums. It is typically because you want to take advantage of the integer
qualities of an enum value, that it is made non-contiguous to begin with.
- Anders
Damn, I can't even make my corrections clear! The oops was that the code I
posted wasn't functionally equivalent to the original.
Paul
Question: for the X above, is ++ really meaningful?
The example would suggest, not.
--
Martin Fabian http://www.s2.chalmers.se/~fabian/
--
"Cheer up. It may never happen" (Edina Monsoon)
/* Remove NOSPAM from reply-to address to mail me */
[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]
Trivially, *if* that's the direction you want to go. You're conflating
two things: The abstract value of the object, and what integer value it
converts to.
The following is a perfectly plausible definition of an abstract
data type X:
1. ValueSet(X) = {a,b,c,d}
2. ++ is defined on {a,b,c} and carries a->b, b->c, c->d.
3. There is a conversion function toInt:X->int defined by
toInt: a->1
toInt: b->5
toInt: c->9
toInt: d->5
You could even write a class with exactly these properties easily
enough.
This doesn't happen to be what enum's are in C++; but then again, enum's
aren't anything particularly clean in C++: They were added very late to
C, forcing them to have poor type properties (since people wanted to use
them as array indicies, which without major surgery to C meant they had
to freely convert to integers, and in C effectly *were* integers); C++
strengthened their type properties a bit, but couldn't go too far if it
wanted to remain reasonably compatible with C; and finally C++ made the
semantics even more complex to allow bit masks to be defined using
enums, destroying what little distinction there ever was between the
interface an implementation of an enum. That's all water under the
bridge now; there's no hope of *enum* being anything other than it is.
But what enum is co-extensive with what an enumerated type could be.
-- Jerry
If ++ is to be meaningful, when applied to an argument of 5, it should
return 6. There's no symbolic label in the enum corresponding to 6,
but with the C++ definition of an enum, 6 is just as valid as a value
of the enum as 5 is.
What would you do with (largest_representable_value_in_enum)++ though?
In the C++ tradition of silent overflows, I guess the answer wouldn't
be to throw, but a silent adjustment to the most negative value
representable by the enum, or zero if all representable values are non-
negative.
Dave
--
Dave Gomboc
da_veATc_sPERIODualb_ertaDOTc_a
(remove underscores and replace MAJUSCULES with punctuation to get
email address)
Sent via Deja.com http://www.deja.com/
Share what you know. Learn what you don't.
[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]
I think you missed the point. We were discussing the implementation of
++ (via a user defined operator function) to return the next enumeration
constant. This is perfectly meaningful if no two enumeration constants
share the same value.
Francis Glassborow Journal Editor, Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]
No, you missed mine: such an overloading of ++ is misleading and
shouldn't be used. IMO, of course.
Dave
--
Dave Gomboc
da_veATc_sPERIODualb_ertaDOTc_a
(remove underscores and replace MAJUSCULES with punctuation to get email
Sent via Deja.com http://www.deja.com/
Share what you know. Learn what you don't.
[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]
I understand what you were saying but that is a value judgement with
which not everyone will agree.
Francis Glassborow Journal Editor, Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]
#include <enumeration>
#include <vector>
void foo()
{
enumeration fruit("apple", "orange", "grapefruit");
vector<fruit> fruitBowl;
fruit myFruit;
fruit anotherFruit;
fruit = "orange";
anotherFruit = fruit.next();
fruit = "pear"; // throws exception
}
The only problem is, I have no idea how to write such a class (or indeed if
it is possible).
James Grant
Dave Gomboc <dave_...@my-deja.com> wrote in message
news:7qnf22$k4l$1...@nnrp1.deja.com...
> In article <f6dyS0A9...@robinton.demon.co.uk>,
> Francis Glassborow <fran...@robinton.demon.co.uk> wrote:
> > In article <7qigm6$vl2$1...@nnrp1.deja.com>, Dave Gomboc <dave_gomboc@my-
> > deja.com> writes
> > >If ++ is to be meaningful, when applied to an argument of 5, it
> should
> > >return 6. There's no symbolic label in the enum corresponding to 6,
> > >but with the C++ definition of an enum, 6 is just as valid as a value
> > >of the enum as 5 is.
> >
> > I think you missed the point. We were discussing the implementation
> of
> > ++ (via a user defined operator function) to return the next
> enumeration
> > constant. This is perfectly meaningful if no two enumeration
> constants
> > share the same value.
>
> No, you missed mine: such an overloading of ++ is misleading and
> shouldn't be used. IMO, of course.
[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]
> Surely what we really need is a class for enumerations, so we could write
> code like this (wild guess at syntax) :
We don't.
> #include <enumeration>
> #include <vector>
>
> void foo()
> {
> enumeration fruit("apple", "orange", "grapefruit");
>
> vector<fruit> fruitBowl;
> fruit myFruit;
> fruit anotherFruit;
>
> fruit = "orange";
> anotherFruit = fruit.next();
>
> fruit = "pear"; // throws exception
> }
>
> The only problem is, I have no idea how to write such a class (or indeed if
> it is possible).
Writting this class is trivial and is not the problem.
The only problem is that's generally a bad idea to use
string litterals where symbolic names can be used. Here
is a resonnable solution (except if you want to introduce
fruit names at runtime):
enum fruit { apple, orange, grapefruit, last_fruit };
fruit next (fruit f)
{
f = fruit(f+1);
if (f == last_fruit)
throw out_of_range ();
return f;
}
--
Valentin Bonnard
#include <iostream>
template <unsigned n, char const * const e[n]>
class enumeration
{
static unsigned lookup(char const *s)
{
unsigned v = std::find(e, e + n, s) - e;
if (v == n)
throw s;
return v;
}
unsigned value;
enumeration(unsigned v) : value(v) { }
public:
enumeration() : value(0) { }
enumeration(char const *s) : value(lookup(s)) { }
enumeration(const enumeration &o) : value(o.value) { }
enumeration &operator=(const enumeration &o)
{
value = o.value;
return *this;
}
enumeration &operator=(char const *s)
{
value = lookup(s);
return *this;
}
enumeration next() const { return enumeration((value + 1) % n); }
enumeration prev() const { return enumeration((value + n - 1) % n); }
friend std::ostream &operator<<(std::ostream &out, const enumeration &v)
{
return out << e[v.value];
}
};
extern char const * const fruits[] = { "apple", "pear", "orange" };
extern char const * const colors[] = { "red", "green", "orange" };
int main()
{
typedef enumeration<3, fruits> fruit;
typedef enumeration<3, colors> color;
fruit a = "pear";
fruit b;
b = a.next();
color c = "red";
color d = c.prev();
cout << b << endl;
cout << d << endl;
> #include <enumeration>
> #include <vector>
> void foo()
> {
> enumeration fruit("apple", "orange", "grapefruit");
> vector<fruit> fruitBowl;
> fruit myFruit;
> fruit anotherFruit;
> fruit = "orange";
> anotherFruit = fruit.next();
> fruit = "pear"; // throws exception
> }
> The only problem is, I have no idea how to write such a class (or indeed if
> it is possible).
Just a fuzzy idea... I think a map using a string as key and an int as
element might do the stuff. It could also enable casting from enum to int,
and even enable two different enum name to have the same value (The "next"
operation would use the order in the map, not the integer value)
--
Loďc
>Surely what we really need is a class for enumerations, so we could write
>code like this (wild guess at syntax) :
>
>#include <enumeration>
>#include <vector>
>
>void foo()
>{
> enumeration fruit("apple", "orange", "grapefruit");
>
> vector<fruit> fruitBowl;
> fruit myFruit;
> fruit anotherFruit;
>
> fruit = "orange";
> anotherFruit = fruit.next();
>
> fruit = "pear"; // throws exception
>}
One can write a class enumeration with constructor like
enumeration::enumeration(const char *)
to parse the list of possible fruit. The class enumeration may
contain a std::set<std::string> to keep track of all the possibile
strings. We may even implement class enumeration in terms of
class parser.
There is some runtime overhead for parsing. On the other hand,
one can create/change possible enums at runtime.
Another approach is to write a program which generates the enum
class like this:
class Fruit {
public:
static const Fruit apple;
static const Fruit orange;
static const Fruit grapefruit;
/* whatever */
private:
int d_val;
explicit Fruit(int val) : d_val(val) { }
};
The program asks you what enums you want, what operators you want,
and a name for the class. The rest is mechanical.
--
--------------
siemel b naran
--------------
This looks like a set:
typedef set<string> enum_fruit;
typedef enum_fruit::iterator fruit;
enum_fruit Allfruit;
Allfruit.insert(string("apple"));
Allfruit.insert(string("orange"));
Allfruit.insert(string("grapefruit"));
fruit MyFruit=Allfruit.find(string("apple");
vector<fruit> fruitBowl;
fruitBowl.push_back(MyFruit);
MyFruit++;
It may be better to make enum_fruit a class, privately
derived from set<string>, and fruit a class, too. This allows
for syntactic sugar: enum_fruit Allfruit could be a static
member of fruit, etc.
>It may be better to make enum_fruit a class, privately
>derived from set<string>, and fruit a class, too. This allows
>for syntactic sugar: enum_fruit Allfruit could be a static
>member of fruit, etc.
We could contain std::set as a private data member too :).
--
--------------
siemel b naran
--------------
[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]