Enumerated type and RNG

Discussion in 'C++' started by mike3, Jan 1, 2010.

  1. mike3

    mike3 Guest

    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?
     
    mike3, Jan 1, 2010
    #1
    1. Advertising

  2. mike3

    James Kanze Guest

    On Jan 1, 11:43 pm, mike3 <> 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
     
    James Kanze, Jan 2, 2010
    #2
    1. Advertising

  3. mike3

    mike3 Guest

    On Jan 2, 11:48 am, James Kanze <> wrote:
    > On Jan 1, 11:43 pm, mike3 <> 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?
     
    mike3, Jan 2, 2010
    #3
  4. mike3

    mike3 Guest

    On Jan 2, 2:27 pm, mike3 <> wrote:
    > On Jan 2, 11:48 am, James Kanze <> wrote:
    >
    >
    >
    > > On Jan 1, 11:43 pm, mike3 <> 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.
     
    mike3, Jan 3, 2010
    #4
  5. mike3

    James Kanze Guest

    On Jan 2, 9:27 pm, mike3 <> wrote:
    > On Jan 2, 11:48 am, James Kanze <> wrote:
    > > On Jan 1, 11:43 pm, mike3 <> 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
     
    James Kanze, Jan 3, 2010
    #5
  6. mike3

    James Kanze Guest

    On Jan 3, 3:27 am, mike3 <> wrote:
    > On Jan 2, 2:27 pm, mike3 <> 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
     
    James Kanze, Jan 3, 2010
    #6
  7. mike3

    mike3 Guest

    On Jan 3, 4:54 am, James Kanze <> wrote:
    > On Jan 3, 3:27 am, mike3 <> wrote:
    >
    > > On Jan 2, 2:27 pm, mike3 <> 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.
     
    mike3, Jan 4, 2010
    #7
  8. mike3

    James Kanze Guest

    On Jan 4, 12:59 am, mike3 <> wrote:
    > On Jan 3, 4:54 am, James Kanze <> wrote:
    > > On Jan 3, 3:27 am, mike3 <> wrote:
    > > > On Jan 2, 2:27 pm, mike3 <> 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
     
    James Kanze, Jan 4, 2010
    #8
  9. mike3

    mike3 Guest

    On Jan 4, 2:56 pm, James Kanze <> wrote:
    > On Jan 4, 12:59 am, mike3 <> 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?
     
    mike3, Jan 9, 2010
    #9
  10. mike3

    James Kanze Guest

    On Jan 9, 9:51 am, mike3 <> wrote:
    > On Jan 4, 2:56 pm, James Kanze <> wrote:


    > > On Jan 4, 12:59 am, mike3 <> 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
     
    James Kanze, Jan 9, 2010
    #10
  11. Am 09.01.2010 14:25, schrieb James Kanze:
    > On Jan 9, 9:51 am, mike3 <> wrote:
    >>>> 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.


    Easiest way would be an enum in a struct. For example:

    /// Don't forget to document this mysterious function
    template <typename Enum>
    typename Enum::type getEnumMax() { return Enum::max; }

    struct Enum1 {
    enum type {
    value1,
    value2,
    max
    };
    };

    In C++0x you can use "enum class" instead.

    --
    Thomas
     
    Thomas J. Gritzan, Jan 9, 2010
    #11
  12. mike3

    James Kanze Guest

    On Jan 9, 2:57 pm, Pete Becker <> wrote:
    > James Kanze wrote:
    > > Because enum's don't introduce scope, however, this would
    > > mean that you cannot have more than one such enum in each
    > > namespace.


    > Fortunately, C++0x will have scoped enums:


    > enum class scoped_enum { a, b, c };
    > enum class another_scoped_enum { b, c, a };


    > scoped_enum::a and another_scoped_enum::a are distinct names.


    Yes, but if I tell my boss that we can't deliver until Visual
    C++ supports scoped_enum, I don't think it will go over too
    well.

    --
    James Kanze
     
    James Kanze, Jan 9, 2010
    #12
  13. mike3

    mike3 Guest

    On Jan 9, 6:25 am, James Kanze <> wrote:
    > On Jan 9, 9:51 am, mike3 <> wrote:

    <snip>
    > 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.
    >


    Hmm. So then what should I do?

    > > 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.)
    >


    What does this "parse enums" thing do and how does it work?
     
    mike3, Jan 10, 2010
    #13
  14. mike3

    James Kanze Guest

    On Jan 10, 5:15 am, mike3 <> wrote:
    > On Jan 9, 6:25 am, James Kanze <> wrote:
    > > On Jan 9, 9:51 am, mike3 <> wrote:

    > <snip>
    > > 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.


    > Hmm. So then what should I do?


    Whatever seems best to you. There is no perfect solution. I've
    presented some of the alternatives, but it's up to you to choose
    which one seems best for you.

    > > > 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.)


    > What does this "parse enums" thing do and how does it work?


    Originally, it was just a bit of lex and a very simple state
    machine, to determine when an enum started, extract its name and
    members, and then write out the necessary code for mapping
    between the enum values and strings. It then got extended to
    handle namespaces and classes, so that it could be used to map
    nested enums, and to generate other things as well; once you've
    collected the information, there are a lot of things you can
    generate easily.

    Another alternative is to invent a little language to describe
    your enums, and generate the enum declaration and any additional
    code you want from that. That's easier even than parsing; it
    tends to work best when the enums are in global scope (but you
    can add options for it to generate e.g. namespaces, and if you
    prefer your enums in classes, you can do that as well). For the
    simplest case, you can even use a small language, like AWK, for
    the generator. (This is doubtlessly the route I would have
    taken, rather than my parser, if I hadn't had to deal with
    legacy code which used enum, and not any little language I could
    invent. And the fact that my enums were often members of a
    larger class.)

    --
    James Kanze
     
    James Kanze, Jan 10, 2010
    #14
  15. mike3

    mike3 Guest

    On Jan 10, 4:21 am, James Kanze <> wrote:
    > On Jan 10, 5:15 am, mike3 <> wrote:
    >
    >
    >
    > > On Jan 9, 6:25 am, James Kanze <> wrote:
    > > > On Jan 9, 9:51 am, mike3 <> wrote:

    > > <snip>
    > > > 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.

    > > Hmm. So then what should I do?

    >
    > Whatever seems best to you.  There is no perfect solution.  I've
    > presented some of the alternatives, but it's up to you to choose
    > which one seems best for you.
    >


    I suppose.

    > > > > 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.)

    > > What does this "parse enums" thing do and how does it work?

    >
    > Originally, it was just a bit of lex and a very simple state
    > machine, to determine when an enum started, extract its name and
    > members, and then write out the necessary code for mapping
    > between the enum values and strings.  It then got extended to
    > handle namespaces and classes, so that it could be used to map
    > nested enums, and to generate other things as well; once you've
    > collected the information, there are a lot of things you can
    > generate easily.
    >
    > Another alternative is to invent a little language to describe
    > your enums, and generate the enum declaration and any additional
    > code you want from that.  That's easier even than parsing; it
    > tends to work best when the enums are in global scope (but you
    > can add options for it to generate e.g. namespaces, and if you
    > prefer your enums in classes, you can do that as well).  For the
    > simplest case, you can even use a small language, like AWK, for
    > the generator.  (This is doubtlessly the route I would have
    > taken, rather than my parser, if I hadn't had to deal with
    > legacy code which used enum, and not any little language I could
    > invent.  And the fact that my enums were often members of a
    > larger class.)
    >


    Mmm. This seems to be highly complicated, far too much for what
    is otherwise a simple problem, even simpler than converting to
    strings.
     
    mike3, Jan 10, 2010
    #15
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Marek Ponca

    Enumerated Type in assertion ?

    Marek Ponca, Jan 10, 2005, in forum: VHDL
    Replies:
    2
    Views:
    3,243
    Jonathan Bromley
    Jan 10, 2005
  2. Nick Bassiliades

    Redefining an enumerated attribute type

    Nick Bassiliades, Dec 9, 2005, in forum: XML
    Replies:
    1
    Views:
    441
    Henry S. Thompson
    Dec 12, 2005
  3. Replies:
    1
    Views:
    378
    Henry S. Thompson
    Mar 6, 2006
  4. David
    Replies:
    0
    Views:
    371
    David
    Mar 1, 2006
  5. Francois Grieu
    Replies:
    7
    Views:
    440
    Ben Bacarisse
    Apr 8, 2009
Loading...

Share This Page