one enum is a subset of another

Discussion in 'C++' started by Christopher, Jan 31, 2012.

  1. Christopher

    Christopher Guest

    A developer before me created a large enumeration we can call
    EnumType1.
    He then, right under it, typedef-ed another

    typedef EnumType1 EnumType2

    He then created a comment "alias, should only include x types", where
    x is a rule defining a subset of EnumType1

    This is crap imo. Any function or method declared to take EnumType2,
    would happily take a value from EnumType1 that does not meet the x
    criteria.

    Since I know the subset from EmunType1 that meets the x criteria, how
    can I define a subset EnumType2 that only includes those enums without
    typing the whole darn subset twice?

    Example
    enum Fruit
    {
    APPLE = 0,
    BANANA,
    ORANGE,
    TANGERINE,
    GRAPEFRUIT,
    NUM_FRUITS
    };

    typedef Fruit Citrus; // This is crap and I want to fix it
    Christopher, Jan 31, 2012
    #1
    1. Advertising

  2. Christopher

    Paul N Guest

    On Jan 31, 10:56 pm, Christopher <> wrote:
    > A developer before me created a large enumeration we can call
    > EnumType1.
    > He then, right under it, typedef-ed another
    >
    > typedef EnumType1 EnumType2
    >
    > He then created a comment "alias, should only include x types", where
    > x is a rule defining a subset of EnumType1
    >
    > This is crap imo. Any function or method declared to take EnumType2,
    > would happily take a value from  EnumType1 that does not meet the x
    > criteria.
    >
    > Since I know the subset from EmunType1 that meets the x criteria, how
    > can I define a subset EnumType2 that only includes those enums without
    > typing the whole darn subset twice?
    >
    > Example
    > enum Fruit
    > {
    >    APPLE = 0,
    >    BANANA,
    >    ORANGE,
    >    TANGERINE,
    >    GRAPEFRUIT,
    >    NUM_FRUITS
    >
    > };
    >
    > typedef Fruit Citrus;   // This is crap and I want to fix it


    I'm not sure you can do what you want. In view of which, what your
    developer has done doesn't seem entirely stupid - the compiler won't
    catch any errors but things are more obvious to a human reader. For
    instance:

    typedef Fruit Apple_or_Banana;

    Apple_or_Banana x;

    x = ORANGE;

    - the compiler won't spot the error, but you can.
    Paul N, Jan 31, 2012
    #2
    1. Advertising

  3. Christopher

    Jorgen Grahn Guest

    On Tue, 2012-01-31, Paul N wrote:
    > On Jan 31, 10:56 pm, Christopher <> wrote:
    >> A developer before me created a large enumeration we can call
    >> EnumType1.
    >> He then, right under it, typedef-ed another
    >>
    >> typedef EnumType1 EnumType2
    >>
    >> He then created a comment "alias, should only include x types", where
    >> x is a rule defining a subset of EnumType1
    >>
    >> This is crap imo. Any function or method declared to take EnumType2,
    >> would happily take a value from  EnumType1 that does not meet the x
    >> criteria.
    >>
    >> Since I know the subset from EmunType1 that meets the x criteria, how
    >> can I define a subset EnumType2 that only includes those enums without
    >> typing the whole darn subset twice?
    >>
    >> Example
    >> enum Fruit
    >> {
    >>    APPLE = 0,
    >>    BANANA,
    >>    ORANGE,
    >>    TANGERINE,
    >>    GRAPEFRUIT,
    >>    NUM_FRUITS
    >>
    >> };
    >>
    >> typedef Fruit Citrus;   // This is crap and I want to fix it

    >
    > I'm not sure you can do what you want. In view of which, what your
    > developer has done doesn't seem entirely stupid - the compiler won't
    > catch any errors but things are more obvious to a human reader.


    Depends on your attitude to typedefs ... I am suspicious them (in this
    usage) because they introduce uncertainty into an area where usually
    the compiler guarantees correctness (i.e. if Fruit and Citrus had been
    classes).

    /Jorgen

    --
    // Jorgen Grahn <grahn@ Oo o. . .
    \X/ snipabacken.se> O o .
    Jorgen Grahn, Jan 31, 2012
    #3
  4. On 31.01.2012 23:56, Christopher wrote:
    > A developer before me created a large enumeration we can call
    > EnumType1.
    > He then, right under it, typedef-ed another
    >
    > typedef EnumType1 EnumType2
    >
    > He then created a comment "alias, should only include x types", where
    > x is a rule defining a subset of EnumType1
    >
    > This is crap imo. Any function or method declared to take EnumType2,
    > would happily take a value from EnumType1 that does not meet the x
    > criteria.


    Exactly. You need different types.

    > Since I know the subset from EmunType1 that meets the x criteria, how
    > can I define a subset EnumType2 that only includes those enums without
    > typing the whole darn subset twice?


    There is no language support for this kind of problem.

    AFAIK you have two options:
    1. repeat the definition of the common constants.
    2. declare your own enum classes.

    In the latter case you need to know that Citrus is no subclass of Fruit,
    because you can safely cast from the subset to the general one but not
    the other way around.

    class Citrus
    {public:
    static const Citrus ORANGE;
    static const Citrus GRAPEFRUIT;
    //...

    protected:
    Citrus() {}
    };

    class Fruit : Citrus
    { static const Fruit APPLE;
    //...
    protected:
    Fruit() {}
    };

    bool operator==(const Citrus& l, const Citrus& r)
    { return &l == &r;
    }
    bool operator!=(const Citrus& l, const Citrus& r)
    { return &l != &r;
    }

    Note that this pseudo enums have no value, since the fixed number of
    instances is already sufficient for uniqueness. This is similar to Java
    2 like enums.

    Things get complicated when you need to define different subsets.
    Especially the comparison operators have to be overloaded appropriately.
    And if you also require an associated int value, you need a virtual base
    class holding that value or alternatively build your own lookup table to
    ensure uniqueness over the related class types.


    Marcel
    Marcel Müller, Feb 1, 2012
    #4
  5. Christopher

    Thomas Boell Guest

    On Tue, 31 Jan 2012 14:56:03 -0800 (PST)
    Christopher <> wrote:

    > A developer before me created a large enumeration we can call
    > EnumType1.
    > He then, right under it, typedef-ed another
    >
    > typedef EnumType1 EnumType2
    >
    > He then created a comment "alias, should only include x types", where
    > x is a rule defining a subset of EnumType1
    >
    > This is crap imo. Any function or method declared to take EnumType2,
    > would happily take a value from EnumType1 that does not meet the x
    > criteria.
    >
    > Since I know the subset from EmunType1 that meets the x criteria, how
    > can I define a subset EnumType2 that only includes those enums without
    > typing the whole darn subset twice?
    >
    > Example
    > enum Fruit
    > {
    > APPLE = 0,
    > BANANA,
    > ORANGE,
    > TANGERINE,
    > GRAPEFRUIT,
    > NUM_FRUITS
    > };
    >
    > typedef Fruit Citrus; // This is crap and I want to fix it


    You could do something like this:

    #define FRUIT_VALUES \
    APPLE, \
    BANANA, \
    ORANGE

    enum Fruit
    {
    FRUIT_VALUES
    };

    enum Things
    {
    FRUIT_VALUES,
    BEERCAN, CAR, ALOT
    };

    Whether using the preprocessor like this is "good style" depends on
    your point of view.
    Thomas Boell, Feb 1, 2012
    #5
  6. Christopher

    Larry Evans Guest

    On 02/01/12 02:51, Marcel Müller wrote:
    > On 31.01.2012 23:56, Christopher wrote:
    >> A developer before me created a large enumeration we can call
    >> EnumType1.
    >> He then, right under it, typedef-ed another
    >>
    >> typedef EnumType1 EnumType2
    >>
    >> He then created a comment "alias, should only include x types", where
    >> x is a rule defining a subset of EnumType1
    >>
    >> This is crap imo. Any function or method declared to take EnumType2,
    >> would happily take a value from EnumType1 that does not meet the x
    >> criteria.

    >
    > Exactly. You need different types.
    >
    >> Since I know the subset from EmunType1 that meets the x criteria, how
    >> can I define a subset EnumType2 that only includes those enums without
    >> typing the whole darn subset twice?

    >
    > There is no language support for this kind of problem.
    >
    > AFAIK you have two options:
    > 1. repeat the definition of the common constants.
    > 2. declare your own enum classes.
    >
    > In the latter case you need to know that Citrus is no subclass of Fruit,
    > because you can safely cast from the subset to the general one but not
    > the other way around.
    >
    > class Citrus
    > {public:
    > static const Citrus ORANGE;
    > static const Citrus GRAPEFRUIT;
    > //...
    >
    > protected:
    > Citrus() {}
    > };
    >
    > class Fruit : Citrus
    > { static const Fruit APPLE;
    > //...
    > protected:
    > Fruit() {}
    > };
    >
    > bool operator==(const Citrus& l, const Citrus& r)
    > { return &l == &r;
    > }
    > bool operator!=(const Citrus& l, const Citrus& r)
    > { return &l != &r;
    > }
    >
    > Note that this pseudo enums have no value, since the fixed number of
    > instances is already sufficient for uniqueness. This is similar to Java
    > 2 like enums.

    [snip]

    Hi Marcel,

    I tried a slightly modified form of your code shown in the attached.
    However, trying to compile it, without the #define DEF_FRUITS, I got the
    error messages:

    ../build/gcc4_6v/gcc.test/enum_static_const.o: In function `main':
    /home/evansl/prog_dev/gcc.test/enum_static_const.cpp:37: undefined
    reference to `Fruit::APPLE'
    /home/evansl/prog_dev/gcc.test/enum_static_const.cpp:38: undefined
    reference to `Citrus::ORANGE'
    collect2: ld returned 1 exit status

    In addition, I'm guessing you meant the copy CTOR's should be private
    too to avoid any other instances of Fruit or Citrus from being
    created. Is that right?

    -regards,
    Larry
    Larry Evans, Feb 1, 2012
    #6
  7. Christopher

    Larry Evans Guest

    On 01/31/12 16:56, Christopher wrote:
    > A developer before me created a large enumeration we can call
    > EnumType1.
    > He then, right under it, typedef-ed another
    >
    > typedef EnumType1 EnumType2
    >
    > He then created a comment "alias, should only include x types", where
    > x is a rule defining a subset of EnumType1
    >
    > This is crap imo. Any function or method declared to take EnumType2,
    > would happily take a value from EnumType1 that does not meet the x
    > criteria.
    >
    > Since I know the subset from EmunType1 that meets the x criteria, how
    > can I define a subset EnumType2 that only includes those enums without
    > typing the whole darn subset twice?
    >
    > Example
    > enum Fruit
    > {
    > APPLE = 0,
    > BANANA,
    > ORANGE,
    > TANGERINE,
    > GRAPEFRUIT,
    > NUM_FRUITS
    > };
    >
    > typedef Fruit Citrus; // This is crap and I want to fix it
    >
    >
    >

    Maybe this thread would help:

    http://groups.google.com/group/comp.lang.c /msg/579f71bf8d783ec0

    -regards,
    Larry
    Larry Evans, Feb 1, 2012
    #7
  8. On 01.02.2012 18:46, Larry Evans wrote:
    > I tried a slightly modified form of your code shown in the attached.
    > However, trying to compile it, without the #define DEF_FRUITS, I got the
    > error messages:
    >
    > ./build/gcc4_6v/gcc.test/enum_static_const.o: In function `main':
    > /home/evansl/prog_dev/gcc.test/enum_static_const.cpp:37: undefined
    > reference to `Fruit::APPLE'
    > /home/evansl/prog_dev/gcc.test/enum_static_const.cpp:38: undefined
    > reference to `Citrus::ORANGE'
    > collect2: ld returned 1 exit status


    You are right. It was no complete code. It only shows the way.

    C++ requires statics to be defined outside the class in a compilation
    unit. I.e.:

    const Citrus Citrus::ORANGE;
    const Citrus Citrus::GRAPEFRUIT;
    const Fruit Fruit::APPLE;
    ....


    > In addition, I'm guessing you meant the copy CTOR's should be private
    > too to avoid any other instances of Fruit or Citrus from being
    > created. Is that right?


    Yes, both. The default constructor need to be private and the object
    should be non-copyable.
    Citrus(const Citrus&) = delete;
    Citrus& operator=(const Citrus&) = delete;
    should do the job.


    Marcel
    Marcel Müller, Feb 1, 2012
    #8
  9. Thomas Boell <> wrote:
    > You could do something like this:
    >
    > #define FRUIT_VALUES \
    > APPLE, \
    > BANANA, \
    > ORANGE
    >
    > enum Fruit
    > {
    > FRUIT_VALUES
    > };
    >
    > enum Things
    > {
    > FRUIT_VALUES,
    > BEERCAN, CAR, ALOT
    > };
    >
    > Whether using the preprocessor like this is "good style" depends on
    > your point of view.


    That's quite dangerous. You have to be sure, that FRUIT_VALUES is always
    the first in the enum, otherwise the values are no more the same in both
    enums.

    I think it should not be possible to have the same name in two different
    enums anyway. I am not sure though.

    Tobi
    Tobias Müller, Feb 1, 2012
    #9
  10. Christopher

    Matt D. Guest

    On 2/1/2012 14:08, Thomas Boell wrote:
    > You could do something like this:
    >
    > #define FRUIT_VALUES \
    > APPLE, \
    > BANANA, \
    > ORANGE
    >
    > enum Fruit
    > {
    > FRUIT_VALUES
    > };
    >
    > enum Things
    > {
    > FRUIT_VALUES,
    > BEERCAN, CAR, ALOT
    > };
    >
    > Whether using the preprocessor like this is "good style" depends on
    > your point of view.


    It's seems very much like inheritance, so it made me think that perhaps
    using something along the following could be of use:
    http://www.codeproject.com/Articles/16150/Inheriting-a-C-enum-type

    Best,

    Matt
    Matt D., Feb 1, 2012
    #10
  11. Christopher

    Thomas Boell Guest

    On Thu, 02 Feb 2012 00:37:15 +0100
    "Matt D." <> wrote:

    > On 2/1/2012 14:08, Thomas Boell wrote:
    > > You could do something like this:
    > >
    > > #define FRUIT_VALUES \
    > > APPLE, \
    > > BANANA, \
    > > ORANGE
    > >
    > > enum Fruit
    > > {
    > > FRUIT_VALUES
    > > };
    > >
    > > enum Things
    > > {
    > > FRUIT_VALUES,
    > > BEERCAN, CAR, ALOT
    > > };
    > >
    > > Whether using the preprocessor like this is "good style" depends on
    > > your point of view.

    >
    > It's seems very much like inheritance, so it made me think that perhaps
    > using something along the following could be of use:
    > http://www.codeproject.com/Articles/16150/Inheriting-a-C-enum-type


    He forgot to start the NewFruits enum values after the end of Fruit, so
    he will not be able to distinguish Apples from Oranges.
    Thomas Boell, Feb 2, 2012
    #11
    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. mrhicks
    Replies:
    2
    Views:
    417
    Dave Thompson
    Jun 10, 2004
  2. Jay Tee
    Replies:
    15
    Views:
    654
    Jay Tee
    Feb 20, 2007
  3. Phlip
    Replies:
    6
    Views:
    1,433
    Peter Flynn
    Apr 23, 2010
  4. Thriving K.
    Replies:
    2
    Views:
    199
    Gennady Bystritsky
    Aug 4, 2009
  5. dblock
    Replies:
    2
    Views:
    654
    Simon Krahnke
    Oct 9, 2011
Loading...

Share This Page