one enum is a subset of another

C

Christopher

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
 
P

Paul N

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

Jorgen Grahn

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
 
M

Marcel Müller

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
 
T

Thomas Boell

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

Larry Evans

Exactly. You need different types.


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
 
L

Larry Evans

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
 
M

Marcel Müller

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
 
T

Tobias Müller

Thomas Boell said:
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
 
M

Matt D.

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
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Staff online

Members online

Forum statistics

Threads
473,767
Messages
2,569,570
Members
45,045
Latest member
DRCM

Latest Threads

Top