Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > Enumerated type and RNG

Reply
Thread Tools

Enumerated type and RNG

 
 
mike3
Guest
Posts: n/a
 
      01-01-2010
Hi.

How could I resolve this C++ programming dilemma?

---
enum smth { ZERO, ONE, TWO, MAX }; // not really labeled this way

void f(smth parameter)
{
( ... )
}

( ... )
f(static_cast<smth>(RNG(MAX))); // RNG generates number from 0 to
MAX-1
( ... )
f(TWO); // f is called with fixed constant
( ... )
f(666); // won't work -- good
( ... )
---

Note the marked bit. f() takes the enumerated type smth, so you can't
just stick "666" in there and cause something bad that way, yet I
also need to pass a randomly obtained value from that list, which
requires a cast. Is it considered good practice to use a cast in this
situation? Would it be better to have f() take an "int" or something
like
that and then include an explicit check in there to see if the value
is
outside 0...MAX-1?

Finally, I suppose one could also do this:
int rand(RNG(MAX));
if(rand == ZERO) f(ZERO);
if(rand == ONE) f(ONE);
if(rand == TWO) f(TWO);

This avoids the cast, but seems to introduce a mantainability defect
and
making the code more susceptible to bugs: if one goes and adds more
values to the enum, then must be added here, too (not just in f()),
and
if this is forgotten about... bug!

What should be done here?
 
Reply With Quote
 
 
 
 
James Kanze
Guest
Posts: n/a
 
      01-02-2010
On Jan 1, 11:43 pm, mike3 <(E-Mail Removed)> wrote:

> How could I resolve this C++ programming dilemma?


> ---
> enum smth { ZERO, ONE, TWO, MAX }; // not really labeled this way


> void f(smth parameter)
> {
> ( ... )
> }


> ( ... )
> f(static_cast<smth>(RNG(MAX))); // RNG generates number from 0 to
> MAX-1
> ( ... )
> f(TWO); // f is called with fixed constant
> ( ... )
> f(666); // won't work -- good
> ( ... )
> ---


> Note the marked bit. f() takes the enumerated type smth, so
> you can't just stick "666" in there and cause something bad
> that way, yet I also need to pass a randomly obtained value
> from that list, which requires a cast. Is it considered good
> practice to use a cast in this situation? Would it be better
> to have f() take an "int" or something like that and then
> include an explicit check in there to see if the value is
> outside 0...MAX-1?


No, however...

> Finally, I suppose one could also do this:
> int rand(RNG(MAX));
> if(rand == ZERO) f(ZERO);
> if(rand == ONE) f(ONE);
> if(rand == TWO) f(TWO);


> This avoids the cast, but seems to introduce a mantainability
> defect and making the code more susceptible to bugs: if one
> goes and adds more values to the enum, then must be added
> here, too (not just in f()), and if this is forgotten about...
> bug!


> What should be done here?


Formally, I guess you probably should use some sort of mapping
array (indexed by the return value of rand), but in practice,
I'd just cast. What I would do, however, is isolate it in a
function, e.g.:

smth
rand( smth max )
{
return static_cast< smth >( rand( +max ); }
// Note the unary +, to force max to an integral
// type and avoid infinite recursion.
}

This way, you don't have casts all over the place.

--
James Kanze
 
Reply With Quote
 
 
 
 
mike3
Guest
Posts: n/a
 
      01-02-2010
On Jan 2, 11:48 am, James Kanze <(E-Mail Removed)> wrote:
> On Jan 1, 11:43 pm, mike3 <(E-Mail Removed)> wrote:
>
>
>
> > How could I resolve this C++ programming dilemma?
> > ---
> > enum smth { ZERO, ONE, TWO, MAX }; // not really labeled this way
> > void f(smth parameter)
> > {
> > ( ... )
> > }
> > ( ... )
> > f(static_cast<smth>(RNG(MAX))); // RNG generates number from 0 to
> > MAX-1
> > ( ... )
> > f(TWO); // f is called with fixed constant
> > ( ... )
> > f(666); // won't work -- good
> > ( ... )
> > ---
> > Note the marked bit. f() takes the enumerated type smth, so
> > you can't just stick "666" in there and cause something bad
> > that way, yet I also need to pass a randomly obtained value
> > from that list, which requires a cast. Is it considered good
> > practice to use a cast in this situation? Would it be better
> > to have f() take an "int" or something like that and then
> > include an explicit check in there to see if the value is
> > outside 0...MAX-1?

>
> No, however...
>
> > Finally, I suppose one could also do this:
> > int rand(RNG(MAX));
> > if(rand == ZERO) f(ZERO);
> > if(rand == ONE) f(ONE);
> > if(rand == TWO) f(TWO);
> > This avoids the cast, but seems to introduce a mantainability
> > defect and making the code more susceptible to bugs: if one
> > goes and adds more values to the enum, then must be added
> > here, too (not just in f()), and if this is forgotten about...
> > bug!
> > What should be done here?

>
> Formally, I guess you probably should use some sort of mapping
> array (indexed by the return value of rand), but in practice,
> I'd just cast. What I would do, however, is isolate it in a
> function, e.g.:
>
> smth
> rand( smth max )
> {
> return static_cast< smth >( rand( +max ); }
> // Note the unary +, to force max to an integral
> // type and avoid infinite recursion.
> }
>
> This way, you don't have casts all over the place.
>


So does this mean that for every enum one wants to use the RNG
to generate a value for, one would need tiny "rand" functions
(inline, presumably)? Where would one put all that stuff?

 
Reply With Quote
 
mike3
Guest
Posts: n/a
 
      01-03-2010
On Jan 2, 2:27*pm, mike3 <(E-Mail Removed)> wrote:
> On Jan 2, 11:48 am, James Kanze <(E-Mail Removed)> wrote:
>
>
>
> > On Jan 1, 11:43 pm, mike3 <(E-Mail Removed)> wrote:

>
> > > How could I resolve this C++ programming dilemma?
> > > ---
> > > enum smth { ZERO, ONE, TWO, MAX }; // not really labeled this way
> > > void f(smth parameter)
> > > {
> > > * ( ... )
> > > }
> > > ( ... )
> > > * f(static_cast<smth>(RNG(MAX))); // RNG generates number from 0 to
> > > MAX-1
> > > ( ... )
> > > * f(TWO); // f is called with fixed constant
> > > ( ... )
> > > * f(666); // won't work -- good
> > > ( ... )
> > > ---
> > > Note the marked bit. f() takes the enumerated type smth, so
> > > you can't just stick "666" in there and cause something bad
> > > that way, yet I also need to pass a randomly obtained value
> > > from that list, which requires a cast. Is it considered good
> > > practice to use a cast in this situation? Would it be better
> > > to have f() take an "int" or something like that and then
> > > include an explicit check in there to see if the value is
> > > outside 0...MAX-1?

>
> > No, however...

>
> > > Finally, I suppose one could also do this:
> > > * int rand(RNG(MAX));
> > > * if(rand == ZERO) f(ZERO);
> > > * if(rand == ONE) f(ONE);
> > > * if(rand == TWO) f(TWO);
> > > This avoids the cast, but seems to introduce a mantainability
> > > defect and making the code more susceptible to bugs: if one
> > > goes and adds more values to the enum, then must be added
> > > here, too (not just in f()), and if this is forgotten about...
> > > bug!
> > > What should be done here?

>
> > Formally, I guess you probably should use some sort of mapping
> > array (indexed by the return value of rand), but in practice,
> > I'd just cast. *What I would do, however, is isolate it in a
> > function, e.g.:

>
> > * * smth
> > * * rand( smth max )
> > * * {
> > * * * * return static_cast< smth >( rand( +max ); }
> > * * * * * * // *Note the unary +, to force max to an integral
> > * * * * * * // *type and avoid infinite recursion.
> > * * }

>
> > This way, you don't have casts all over the place.

>
> So does this mean that for every enum one wants to use the RNG
> to generate a value for, one would need tiny "rand" functions
> (inline, presumably)? Where would one put all that stuff?


Could one use a template? Like this?:

---
template<class E>
inline E rand(E max)
{
return(static_cast<E>(rand(+max)));
}
---

Then we need only one definition.
 
Reply With Quote
 
James Kanze
Guest
Posts: n/a
 
      01-03-2010
On Jan 2, 9:27 pm, mike3 <(E-Mail Removed)> wrote:
> On Jan 2, 11:48 am, James Kanze <(E-Mail Removed)> wrote:
> > On Jan 1, 11:43 pm, mike3 <(E-Mail Removed)> wrote:


> > > How could I resolve this C++ programming dilemma?
> > > ---
> > > enum smth { ZERO, ONE, TWO, MAX }; // not really labeled this way
> > > void f(smth parameter)
> > > {
> > > ( ... )
> > > }
> > > ( ... )
> > > f(static_cast<smth>(RNG(MAX))); // RNG generates number from 0 to
> > > MAX-1
> > > ( ... )
> > > f(TWO); // f is called with fixed constant
> > > ( ... )
> > > f(666); // won't work -- good
> > > ( ... )
> > > ---
> > > Note the marked bit. f() takes the enumerated type smth, so
> > > you can't just stick "666" in there and cause something bad
> > > that way, yet I also need to pass a randomly obtained value
> > > from that list, which requires a cast. Is it considered good
> > > practice to use a cast in this situation? Would it be better
> > > to have f() take an "int" or something like that and then
> > > include an explicit check in there to see if the value is
> > > outside 0...MAX-1?


> > No, however...


> > > Finally, I suppose one could also do this:
> > > int rand(RNG(MAX));
> > > if(rand == ZERO) f(ZERO);
> > > if(rand == ONE) f(ONE);
> > > if(rand == TWO) f(TWO);
> > > This avoids the cast, but seems to introduce a mantainability
> > > defect and making the code more susceptible to bugs: if one
> > > goes and adds more values to the enum, then must be added
> > > here, too (not just in f()), and if this is forgotten about...
> > > bug!
> > > What should be done here?


> > Formally, I guess you probably should use some sort of
> > mapping array (indexed by the return value of rand), but in
> > practice, I'd just cast. What I would do, however, is
> > isolate it in a function, e.g.:


> > smth
> > rand( smth max )
> > {
> > return static_cast< smth >( rand( +max ); }
> > // Note the unary +, to force max to an integral
> > // type and avoid infinite recursion.
> > }


> > This way, you don't have casts all over the place.


> So does this mean that for every enum one wants to use the RNG
> to generate a value for, one would need tiny "rand" functions
> (inline, presumably)?


And how many is that? Formally, enum types don't support random
generation in C++, so it's up to you to implement it if you need
it. Just as you do for most other stuff concerning enums
(iterators, | and & operators, etc.).

> Where would one put all that stuff?


Where ever you put the implementation of any other functions
associated with the enum.

Enums, in C++, are a bit funny. They're designed to fulfill at
least two needs, and so do neither completely, since the
operations required to fulfil one of the needs don't make sense
when the enum is used for the other need. (Increment doesn't
make sense when the enum is used to define bit masks, and & and
| don't make sense when the enum is used to define an
enumeration.)

--
James Kanze
 
Reply With Quote
 
James Kanze
Guest
Posts: n/a
 
      01-03-2010
On Jan 3, 3:27 am, mike3 <(E-Mail Removed)> wrote:
> On Jan 2, 2:27 pm, mike3 <(E-Mail Removed)> wrote:


[...]
> Could one use a template? Like this?:


> ---
> template<class E>
> inline E rand(E max)
> {
> return(static_cast<E>(rand(+max)));
> }
> ---


Probably, but I'd worry about ambiguities when calling rand,
potentially resulting in infinite recursion. Maybe if you put
it in a special namespace, however.

What we'd really like, of course, is some means of automatically
getting the maximum value, so that you could write:
SomeEnum e = rand< SomeEnum >();
(This can be done if you explicitely instantiate
std::numeric_limits for each enum type. Very elegant solution,
but probably a case of the cure being worse than the disease;
it's a lot of code to write.)

> Then we need only one definition.


Again, how often does the case occur?

--
James Kanze
 
Reply With Quote
 
mike3
Guest
Posts: n/a
 
      01-04-2010
On Jan 3, 4:54 am, James Kanze <(E-Mail Removed)> wrote:
> On Jan 3, 3:27 am, mike3 <(E-Mail Removed)> wrote:
>
> > On Jan 2, 2:27 pm, mike3 <(E-Mail Removed)> wrote:

>
> [...]
>
> > Could one use a template? Like this?:
> > ---
> > template<class E>
> > inline E rand(E max)
> > {
> > return(static_cast<E>(rand(+max)));
> > }
> > ---

>
> Probably, but I'd worry about ambiguities when calling rand,
> potentially resulting in infinite recursion. Maybe if you put
> it in a special namespace, however.
>


Couldn't one also just call the RNG function something else,
and then go through this to access it for different types?

> What we'd really like, of course, is some means of automatically
> getting the maximum value, so that you could write:
> SomeEnum e = rand< SomeEnum >();
> (This can be done if you explicitely instantiate
> std::numeric_limits for each enum type. Very elegant solution,
> but probably a case of the cure being worse than the disease;
> it's a lot of code to write.)
>


I suppose. It's easier to just have a "max" at the end of the enums.

> > Then we need only one definition.

>
> Again, how often does the case occur?
>


Not sure what the final number will be, but it'd be more than just
one or two.

 
Reply With Quote
 
James Kanze
Guest
Posts: n/a
 
      01-04-2010
On Jan 4, 12:59 am, mike3 <(E-Mail Removed)> wrote:
> On Jan 3, 4:54 am, James Kanze <(E-Mail Removed)> wrote:
> > On Jan 3, 3:27 am, mike3 <(E-Mail Removed)> wrote:
> > > On Jan 2, 2:27 pm, mike3 <(E-Mail Removed)> wrote:


> > [...]


> > > Could one use a template? Like this?:
> > > ---
> > > template<class E>
> > > inline E rand(E max)
> > > {
> > > return(static_cast<E>(rand(+max)));
> > > }
> > > ---


> > Probably, but I'd worry about ambiguities when calling rand,
> > potentially resulting in infinite recursion. Maybe if you
> > put it in a special namespace, however.


> Couldn't one also just call the RNG function something else,
> and then go through this to access it for different types?


Certainly. One could also define a template class, instantiated
on the enum type, and call a member function of it. There are
any number of solutions. (I would, in fact, use the template
class solution. But mainly because my random number generator
is already a class, designed for derivation to support such
things.)

> > What we'd really like, of course, is some means of
> > automatically getting the maximum value, so that you could
> > write:
> > SomeEnum e = rand< SomeEnum >();
> > (This can be done if you explicitely instantiate
> > std::numeric_limits for each enum type. Very elegant
> > solution, but probably a case of the cure being worse than
> > the disease; it's a lot of code to write.)


> I suppose. It's easier to just have a "max" at the end of the
> enums.


Yes, but the problem is accessing it from a template. Enums
don't (at present) introduce a new scope, so two templates in
the same scope can't both define an element max. And if the
name is different (to reflect the enum type), then you're
screwed with regards to templates.

--
James Kanze
 
Reply With Quote
 
mike3
Guest
Posts: n/a
 
      01-09-2010
On Jan 4, 2:56*pm, James Kanze <(E-Mail Removed)> wrote:
> On Jan 4, 12:59 am, mike3 <(E-Mail Removed)> wrote:

<snip>
> > Couldn't one also just call the RNG function something else,
> > and then go through this to access it for different types?

>
> Certainly. *One could also define a template class, instantiated
> on the enum type, and call a member function of it. *There are
> any number of solutions. *(I would, in fact, use the template
> class solution. *But mainly because my random number generator
> is already a class, designed for derivation to support such
> things.)
>


You mean like make the RNG bit a class itself, that you then declare
variables as a type of? But then you still have the problem of
getting the right max.

> > I suppose. It's easier to just have a "max" at the end of the
> > enums.

> Yes, but the problem is accessing it from a template. Enums
> don't (at present) introduce a new scope, so two templates in
> the same scope can't both define an element max. And if the
> name is different (to reflect the enum type), then you're
> screwed with regards to templates.


How does the using different names "screw it" with regards to
templates? You mean because one has to sort of "specify the type
twice", once in the template, the next in the max? How can one
avoid this? How do you do it with your RNG?
 
Reply With Quote
 
James Kanze
Guest
Posts: n/a
 
      01-09-2010
On Jan 9, 9:51 am, mike3 <(E-Mail Removed)> wrote:
> On Jan 4, 2:56 pm, James Kanze <(E-Mail Removed)> wrote:


> > On Jan 4, 12:59 am, mike3 <(E-Mail Removed)> wrote:

> <snip>
> > > Couldn't one also just call the RNG function something
> > > else, and then go through this to access it for different
> > > types?


> > Certainly. One could also define a template class,
> > instantiated on the enum type, and call a member function of
> > it. There are any number of solutions. (I would, in fact,
> > use the template class solution. But mainly because my
> > random number generator is already a class, designed for
> > derivation to support such things.)


> You mean like make the RNG bit a class itself, that you then
> declare variables as a type of? But then you still have the
> problem of getting the right max.


Yes. My idea was to have a template class calling rand() (or
some other generator), with the max value a template argument.

> > > I suppose. It's easier to just have a "max" at the end of the
> > > enums.

> > Yes, but the problem is accessing it from a template. Enums
> > don't (at present) introduce a new scope, so two templates in
> > the same scope can't both define an element max. And if the
> > name is different (to reflect the enum type), then you're
> > screwed with regards to templates.


> How does the using different names "screw it" with regards to
> templates? You mean because one has to sort of "specify the type
> twice", once in the template, the next in the max?


More or less. The template has to know the type name, in order
to declare the return type, and it needs to know the maximum
value. If enums created a scope, you could simply require that
the enum define a reserved entry, max, and the maximum value, in
the template, would be T::max. Because enum's don't introduce
scope, however, this would mean that you cannot have more than
one such enum in each namespace. And if the name is T_max, or
some such (with the name of the type embedded), you can't access
it in the template.

The classical solution for this is a traits template class, the
standard even provides one which you can specialize
(std::numeric_limits), but it requires defining a lot more than
you need here.

> How can one avoid this? How do you do it with your RNG?


I don't. I've never actually needed a random enum, so I'm just
speculating on solutions. If I did need one... I already have
code which can parse enums (originally in order to generate a
mapping between strings and the enum values); it would be
trivial to add support for rand to it, and generate the required
classes or whatever automatically. (Note that there can be some
tricky aspects. When I added generation for iterators, I needed
a type which would hold "one past the end". Since I only
support iterators for enums with no user defined values, I just
used "unsigned"---it seems a reasonable restriction that my code
won't support an enum with more than UINT_MAX-1 members. I
suspect that a similar constraint would be acceptable in your
case.)

--
James Kanze
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
construction of a uniform double RNG from a random bits RNG Francois Grieu C Programming 7 04-07-2009 11:19 PM
define attribute as NOT a member of enumerated type davidmcb@pacbell.net XML 1 03-06-2006 05:16 AM
define attribute as NOT a member of enumerated type David XML 0 03-01-2006 01:11 PM
Redefining an enumerated attribute type Nick Bassiliades XML 1 12-12-2005 01:21 PM
Enumerated Type in assertion ? Marek Ponca VHDL 2 01-10-2005 10:32 AM



Advertisments