Enumerations

Discussion in 'C++' started by Christopher Benson-Manica, Jul 21, 2004.

  1. I'll try to explain what I want to do:

    I have foo.h and foo.cpp. Units that include foo.h will define an
    enumeration bar:

    enum bar { typeNone, typeBaz, typeQuux, ... , count };

    A method defined in foo.cpp needs to return typeNone. Is using

    static_cast< bar >( 0 )

    acceptable?

    Also, methods in foo.cpp need to return typeBaz, typeQuux, etc. Is
    there any way to specify that these are values of the bar enumeration
    without actually defining bar (since units that include foo.h will
    take care of that)?

    --
    Christopher Benson-Manica | I *should* know what I'm talking about - if I
    ataru(at)cyberspace.org | don't, I need to know. Flames welcome.
    Christopher Benson-Manica, Jul 21, 2004
    #1
    1. Advertising

  2. Christopher Benson-Manica

    Steve Guest

    On 21/7/04 8:46 pm, in article cdmh6d$5mk$, "Christopher
    Benson-Manica" <> wrote:

    > I'll try to explain what I want to do:
    >
    > I have foo.h and foo.cpp. Units that include foo.h will define an
    > enumeration bar:
    >
    > enum bar { typeNone, typeBaz, typeQuux, ... , count };
    >
    > A method defined in foo.cpp needs to return typeNone. Is using
    >
    > static_cast< bar >( 0 )
    >
    > acceptable?



    Am I missing something obvious? Why not just return typeNone?


    > Also, methods in foo.cpp need to return typeBaz, typeQuux, etc. Is
    > there any way to specify that these are values of the bar enumeration
    > without actually defining bar (since units that include foo.h will
    > take care of that)?



    Is foo.cpp #including foo.h?


    Steve.
    Steve, Jul 21, 2004
    #2
    1. Advertising

  3. Christopher Benson-Manica

    Steve Guest

    On 21/7/04 8:50 pm, in article BD248795.89586%root@127.0.0.1, "Steve"
    <root@127.0.0.1> wrote:

    > On 21/7/04 8:46 pm, in article cdmh6d$5mk$, "Christopher
    > Benson-Manica" <> wrote:
    >
    >> I'll try to explain what I want to do:
    >>
    >> I have foo.h and foo.cpp. Units that include foo.h will define an
    >> enumeration bar:
    >>
    >> enum bar { typeNone, typeBaz, typeQuux, ... , count };
    >>
    >> A method defined in foo.cpp needs to return typeNone. Is using
    >>
    >> static_cast< bar >( 0 )
    >>
    >> acceptable?

    >
    >
    > Am I missing something obvious? Why not just return typeNone?
    >
    >
    >> Also, methods in foo.cpp need to return typeBaz, typeQuux, etc. Is
    >> there any way to specify that these are values of the bar enumeration
    >> without actually defining bar (since units that include foo.h will
    >> take care of that)?

    >
    >
    > Is foo.cpp #including foo.h?
    >
    >
    > Steve.
    >



    Oops, sorry, let me read the OP again more closely...

    OK, let me rephrase my answer...

    Why not put the enum declaration in foo.h?


    Steve.
    Steve, Jul 21, 2004
    #3
  4. Steve <root@127.0.0.1> spoke thus:

    > Am I missing something obvious? Why not just return typeNone?


    My intent is that neither foo.h nor foo.cpp will actually define bar,
    perhaps something like

    foo.h:

    enum bar;

    foo.cpp

    #include "foo.h"

    /* whatever

    my_special_unit.cpp:

    #include "foo.h"

    enum bar { typeNone, typeBaz, count };

    some_other_unit.cpp:

    #include "foo.h"

    enum bar { typeNone, typeQuux, typeCharlie, count };

    Presumably this won't work, since the bar enumeration is never fleshed
    out for foo.cpp. Basically, I want to make the symbols that the
    enumeration will use available to foo.cpp without actually defining
    the enumeration there. Does that make sense? Is it possible?

    --
    Christopher Benson-Manica | I *should* know what I'm talking about - if I
    ataru(at)cyberspace.org | don't, I need to know. Flames welcome.
    Christopher Benson-Manica, Jul 21, 2004
    #4
  5. Christopher Benson-Manica wrote:
    > Steve <root@127.0.0.1> spoke thus:
    >
    >
    >>Am I missing something obvious? Why not just return typeNone?

    >
    >
    > My intent is that neither foo.h nor foo.cpp will actually define bar,
    > perhaps something like
    >
    > foo.h:
    >
    > enum bar;
    >
    > foo.cpp
    >
    > #include "foo.h"
    >
    > /* whatever
    >
    > my_special_unit.cpp:
    >
    > #include "foo.h"
    >
    > enum bar { typeNone, typeBaz, count };
    >
    > some_other_unit.cpp:
    >
    > #include "foo.h"
    >
    > enum bar { typeNone, typeQuux, typeCharlie, count };
    >
    > Presumably this won't work, since the bar enumeration is never fleshed
    > out for foo.cpp. Basically, I want to make the symbols that the
    > enumeration will use available to foo.cpp without actually defining
    > the enumeration there. Does that make sense? Is it possible?


    If you need to use the enum as a return type and the function must be
    declared in the .h file (which is the case if I understood the original
    question correctly) the answer is no. Only if the enum is used only
    inside function in the .cpp file but never as return type or argument
    the enum can be declared inside the .cpp file.

    In case of a class you might consider putting the enum definition in the
    private section of the class. That way it is clear that the enum is
    intended for internal use only, and isn't accessible to the outside
    world. Another advantage is that it is defined within the scope of the
    class, so potential name clashes are avoided.


    --
    Peter van Merkerk
    peter.van.merkerk(at)dse.nl
    Peter van Merkerk, Jul 21, 2004
    #5
  6. Peter van Merkerk <> spoke thus:

    > In case of a class you might consider putting the enum definition in the
    > private section of the class. That way it is clear that the enum is
    > intended for internal use only, and isn't accessible to the outside
    > world. Another advantage is that it is defined within the scope of the
    > class, so potential name clashes are avoided.


    Well, here's another question: If I put the enum definition in the
    class, can a subclass override that definition?

    --
    Christopher Benson-Manica | I *should* know what I'm talking about - if I
    ataru(at)cyberspace.org | don't, I need to know. Flames welcome.
    Christopher Benson-Manica, Jul 21, 2004
    #6
  7. Christopher Benson-Manica

    JKop Guest

    Without passing judgement on your design:

    extern enum bar;

    return bar(0);


    -JKop
    JKop, Jul 21, 2004
    #7
  8. JKop <> spoke thus:

    > Without passing judgement on your design:


    No, please do! Seriously - otherwise, how do I learn how to improve? :)

    --
    Christopher Benson-Manica | I *should* know what I'm talking about - if I
    ataru(at)cyberspace.org | don't, I need to know. Flames welcome.
    Christopher Benson-Manica, Jul 21, 2004
    #8
  9. Christopher Benson-Manica

    JKop Guest

    Christopher Benson-Manica posted:

    > JKop <> spoke thus:
    >
    >> Without passing judgement on your design:

    >
    > No, please do! Seriously - otherwise, how do I learn how to improve? :)
    >


    First I'm going to talk about enums. They're pretty much useless. For
    instance:

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

    int main()
    {
    Month my_super_duper_month(13);
    }


    So why are they useful? They're only merit is with switch statements:


    switch (some_month)
    {
    case Jan:
    //blah
    case Feb:

    //blah

    }


    The compiler can warn you when you leave one out of the switch statement.
    Yipee!

    Anyway, I'd suggest you return an "unsigned char" from this function. If you
    want to give certain numbers special names, then by all means:

    namespace ChocolateValues
    {
    const unsigned char no_error = 0;
    const unsigned char multiple_errors = 1;
    };

    unsigned char SomeFunction()
    {
    return ChocolateValues::no_error;
    }




    -JKop
    JKop, Jul 21, 2004
    #9
  10. JKop wrote:
    > First I'm going to talk about enums. They're pretty much useless. For
    > instance:


    you have some serious misconceptions about enumerations.

    > enum Month
    > {
    > Jan = 1,
    > Feb = 2,
    > Mar = 3,
    > Apr = 4,
    > May = 5,
    > Jun = 6,
    > Jul = 7,
    > Aug = 8,
    > Sep = 9,
    > Oct = 10,
    > Nov = 11,
    > Dec = 12
    > };
    >
    > int main()
    > {
    > Month my_super_duper_month(13);
    > }


    compiler error - illegal implicit conversion to int.

    mind you:

    Month m(static_cast<Month>(13));

    would work. but that is a case of directly and maliciously circumventing
    the enumeration.

    > So why are they useful? They're only merit is with switch statements:
    >
    >
    > switch (some_month)
    > {
    > case Jan:
    > //blah
    > case Feb:
    >
    > //blah
    >
    > }
    >
    >
    > The compiler can warn you when you leave one out of the switch statement.
    > Yipee!


    what compiler? i would find it quite bizarre if a compiler barked that
    warning at me, unless it had some crazy super verbose warning setting.
    it is not an error, or even a mistake, to only switch on certain
    enumerators.

    > Anyway, I'd suggest you return an "unsigned char" from this function. If you
    > want to give certain numbers special names, then by all means:
    >
    > namespace ChocolateValues
    > {
    > const unsigned char no_error = 0;
    > const unsigned char multiple_errors = 1;
    > };
    >
    > unsigned char SomeFunction()
    > {
    > return ChocolateValues::no_error;
    > }


    and this has to be the wackiest suggestion of all, considering that you
    write off enums for having an implicit conversion to int above (which
    they don't, as i pointed out).

    in fact, the example above is LESS robust than if it had used enums.
    consider this:

    ////////////////////////////////////////////////////////

    namespace error {
    const unsigned char no_error = 0;
    const unsigned char out_of_memory = 1;
    const unsigned char cannot_open_file = 2;
    }

    enum type {
    no_error,
    out_of_memory,
    cannot_open_file
    };

    void print_error(unsigned char c) {
    // print error message based on error code
    switch (c) {
    case error::no_error: // whatever
    case error::eek:ut_of_memory: // whatever
    case error::cannot_open_file: // whatever
    // ...
    }
    }

    // nothing seems wrong with this...
    unsigned char oops = 3;

    // ...but
    print_error(oops); // <--- what should this do?

    ////////////////////////////////////////////////////////

    as opposed to:

    ////////////////////////////////////////////////////////

    namespace error {

    enum type {
    no_error,
    out_of_memory,
    cannot_open_file
    };

    }

    void print_error(error::type c) {
    // print error message based on error code
    switch (c) {
    case error::no_error: // whatever
    case error::eek:ut_of_memory: // whatever
    case error::cannot_open_file: // whatever
    // ...
    }
    }

    error::type nope = 3; // won't compile

    // this is explicit and obvious - the programmer knew what (s)he
    // was doing, and should be able to explain him/herself
    error::type iffy = static_cast<error::type>(3);

    error::type ok = error::eek:ut_of_memory; // obviously ok

    ////////////////////////////////////////////////////////

    enumerations are not perfect - personally, i was looking for a better
    solution just last week, and i was not satisfied with the options - but
    until the standard committee gives the thumbs up to the new super enums,
    we're stuck with them. despite all their shortcomings though, i'd have
    to say they're still a better choice than simple ints (or unsigned
    char's for that matter).

    indi
    Mark A. Gibbs, Jul 22, 2004
    #10
  11. Christopher Benson-Manica wrote:
    > Peter van Merkerk <> spoke thus:
    >
    >>In case of a class you might consider putting the enum definition in the
    >>private section of the class. That way it is clear that the enum is
    >>intended for internal use only, and isn't accessible to the outside
    >>world. Another advantage is that it is defined within the scope of the
    >>class, so potential name clashes are avoided.

    >
    > Well, here's another question: If I put the enum definition in the
    > class, can a subclass override that definition?


    I'm afraid not.

    --
    Peter van Merkerk
    peter.van.merkerk(at)dse.nl
    Peter van Merkerk, Jul 22, 2004
    #11
  12. Christopher Benson-Manica

    JKop Guest

    Mark A. Gibbs posted:

    > would work. but that is a case of directly and

    maliciously
    > circumventing the enumeration.



    Month blah = Month(13);


    > error::type nope = 3; // won't compile


    = EnumName(3); //*will* compile, regardless if the enum
    contains a 3.

    -JKOp
    JKop, Jul 22, 2004
    #12
  13. JKop <> spoke thus:

    > = EnumName(3); //*will* compile, regardless if the enum
    > contains a 3.


    Granted, but why on earth would you want to do *that*?

    --
    Christopher Benson-Manica | I *should* know what I'm talking about - if I
    ataru(at)cyberspace.org | don't, I need to know. Flames welcome.
    Christopher Benson-Manica, Jul 22, 2004
    #13
  14. Peter van Merkerk <> spoke thus:

    > I'm afraid not.


    No, no need to be afraid ;)

    --
    Christopher Benson-Manica | I *should* know what I'm talking about - if I
    ataru(at)cyberspace.org | don't, I need to know. Flames welcome.
    Christopher Benson-Manica, Jul 22, 2004
    #14
  15. Christopher Benson-Manica

    tom_usenet Guest

    On Wed, 21 Jul 2004 19:46:21 +0000 (UTC), Christopher Benson-Manica
    <> wrote:

    >I'll try to explain what I want to do:
    >
    >I have foo.h and foo.cpp. Units that include foo.h will define an
    >enumeration bar:
    >
    >enum bar { typeNone, typeBaz, typeQuux, ... , count };
    >
    >A method defined in foo.cpp needs to return typeNone. Is using
    >
    >static_cast< bar >( 0 )
    >
    >acceptable?
    >
    >Also, methods in foo.cpp need to return typeBaz, typeQuux, etc. Is
    >there any way to specify that these are values of the bar enumeration
    >without actually defining bar (since units that include foo.h will
    >take care of that)?


    All definitions of bar must be token for token identical according to
    the one definition rule. If they aren't, you've got undefined
    behaviour.

    In your case you might just want to return some named constants, and
    have other TUs cast them to whatever enum type they want (and
    presumably a different one for each TU).

    Tom
    tom_usenet, Jul 22, 2004
    #15
  16. Christopher Benson-Manica

    JKop Guest

    Christopher Benson-Manica posted:

    > JKop <> spoke thus:
    >
    >> = EnumName(3); //*will* compile, regardless if the enum

    contains a
    >> 3.

    >
    > Granted, but why on earth would you want to do *that*?
    >


    Because it can be done. If you write a function that takes
    a month, then you've to check that it's >= 1 and <= 12.
    Therefore, what use has an enum? Why not just use constant
    variables?

    namespace Month{
    const unsigned char jan = 1,
    feb = 2,
    mar = 3,
    apr = 4,
    may = 5,
    jun = 6,
    //and so on


    -JKop
    JKop, Jul 22, 2004
    #16
  17. Christopher Benson-Manica

    Andre Kostur Guest

    JKop <> wrote in news:zhPLc.5236$:

    > Christopher Benson-Manica posted:
    >
    >> JKop <> spoke thus:
    >>
    >>> = EnumName(3); //*will* compile, regardless if the enum

    > contains a
    >>> 3.

    >>
    >> Granted, but why on earth would you want to do *that*?
    >>

    >
    > Because it can be done. If you write a function that takes


    So can dereferencing a NULL pointer, and reinterpret_casting stuff between
    incompatable types. Doesn't mean that it's defined behaviour.

    > a month, then you've to check that it's >= 1 and <= 12.
    > Therefore, what use has an enum? Why not just use constant
    > variables?


    No you don't. Your function simply takes a Month as a parameter. No need
    to check for range. Your caller would have to invoke undefined behaviour
    to break your function then.
    Andre Kostur, Jul 22, 2004
    #17
  18. Christopher Benson-Manica

    Jeff Flinn Guest

    "Christopher Benson-Manica" <> wrote in message
    news:cdoc6j$ftb$...
    > JKop <> spoke thus:
    >
    > > = EnumName(3); //*will* compile, regardless if the enum
    > > contains a 3.

    >
    > Granted, but why on earth would you want to do *that*?


    I think he means, how would you keep a user from inadvertently doing that
    via a compiler error.

    Jeff F
    Jeff Flinn, Jul 22, 2004
    #18
  19. Christopher Benson-Manica

    Old Wolf Guest

    Andre Kostur <> wrote:

    [snip - debate over whether to use 'enum' for month names]

    > No you don't. Your function simply takes a Month as a parameter. No need
    > to check for range. Your caller would have to invoke undefined behaviour
    > to break your function then.


    If an enum contains values 1...11, then it can also hold values 12...15
    without causing undefined behaviour. This language rule exists to allow
    'flag' enums, eg:

    enum flags
    {
    Foo = 0x80,
    Bar = 0x40,
    Quz = 0x20,
    };

    flags f = Foo | Quz; // 0xA0 is not an enum member, but is valid

    So you still have to check range (> 0 as well as <= 12)
    Old Wolf, Jul 22, 2004
    #19
  20. Christopher Benson-Manica

    Andre Kostur Guest

    (Old Wolf) wrote in
    news::

    > Andre Kostur <> wrote:
    >
    > [snip - debate over whether to use 'enum' for month names]
    >
    >> No you don't. Your function simply takes a Month as a parameter. No
    >> need to check for range. Your caller would have to invoke undefined
    >> behaviour to break your function then.

    >
    > If an enum contains values 1...11, then it can also hold values
    > 12...15 without causing undefined behaviour. This language rule exists
    > to allow 'flag' enums, eg:


    I stand corrected. The enum may contain values beyond the specified ones.

    I guess, for me, that would leave it in the realm of "bad programming
    practice". One would need to explicitly do something to put the enum out
    of range (explicit construction with an out of range value, or do some sort
    of bitwise or arithmetic operations on the enums)
    Andre Kostur, Jul 22, 2004
    #20
    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. clintonG

    HttpStatusCode Enumerations...

    clintonG, May 5, 2004, in forum: ASP .Net
    Replies:
    4
    Views:
    3,939
    clintonG
    May 6, 2004
  2. exquisitus
    Replies:
    12
    Views:
    22,405
    Tilman Bohn
    Feb 19, 2005
  3. exquisitus
    Replies:
    2
    Views:
    449
    Tor Iver Wilhelmsen
    Apr 24, 2005
  4. Chanchal
    Replies:
    4
    Views:
    401
    Thomas Hawtin
    Nov 29, 2005
  5. Joyce
    Replies:
    1
    Views:
    2,077
    Stan Kitsis [MSFT]
    Feb 18, 2005
Loading...

Share This Page