Extend enumeration types?

M

Marcel Müller

Hi,

is there any smart solution for something like sub classes of
enumeration types?

Let's say we have

enum A
{ Value1,
Value2,
Value3
};

enum B
{ Value1,
Value2,
Value3,
Value4,
Value5
};

then enum B can hold all values that A allows and a few more. (Of
course, they cannot exist in the same namespace or class because of the
duplicate names.)
An implicit conversion from A to B is also reasonable. OK, one should
not call this inheritance since the conversion is in the other direction.

Now I would like to define a type B with exactly that properties and
preferably without retyping all the values of A.

I could write classes with a limited set constant values but this has
several drawbacks. First of all no more automatic enumeration of the
values. But also A must no longer be defined as part of a C-API. And
last but not least I loose the automatic choice of the appropriate data
type.

How do others solve comparable tasks?


Marcel
 
F

Francesco

Hi,

is there any smart solution for something like sub classes of
enumeration types?

Let's say we have

enum A
{ Value1,
   Value2,
   Value3

};

enum B
{ Value1,
   Value2,
   Value3,
   Value4,
   Value5

};

then enum B can hold all values that A allows and a few more. (Of
course, they cannot exist in the same namespace or class because of the
duplicate names.)
An implicit conversion from A to B is also reasonable. OK, one should
not call this inheritance since the conversion is in the other direction.

Now I would like to define a type B with exactly that properties and
preferably without retyping all the values of A.

I could write classes with a limited set constant values but this has
several drawbacks. First of all no more automatic enumeration of the
values. But also A must no longer be defined as part of a C-API. And
last but not least I loose the automatic choice of the appropriate data
type.

How do others solve comparable tasks?

Marcel

Hi Marcel, could you please explain the task a bit deeper?

I honestly wasn't able to figure out how you would use such an union
of enums - well, I could, but my imagination has already proved to be
too convolute :) - maybe you're wanting to use enums for something
that is better expressed in C++ via some other kind of abstraction and
somebody here could help you get the same result without having to
merge them.

Cheers,
Francesco
 
M

Marcel Müller

Francesco said:
Hi Marcel, could you please explain the task a bit deeper?

I honestly wasn't able to figure out how you would use such an union
of enums - well, I could, but my imagination has already proved to be
too convolute :) - maybe you're wanting to use enums for something
that is better expressed in C++ via some other kind of abstraction and
somebody here could help you get the same result without having to
merge them.

Let's say I have an observable pattern 'O' in a C API. It calls a
callback function '*cb' with a event type (the enumeration 'A') and a
few other parameters. (I am talking about notifications about
asynchronous changes of information.)

void set_observer(
O obj,
void (*cb)(O obj, A type, void* param),
void* param );

Now I have a C++ application which has objects 'O2' that depend on 'O'
in a way that they add additional features. They are also observables.
But their event type of type 'B' has additional values for changes of
the new features. All events of the base object 'O' are forwarded to the
observers of 'O2' but the observers may receive additional event types.

Now I could map any possibly value of A to a value of B by a large
switch statement or do a hard cast while making implications about the
values of A are defined in B in the same way (as Paavo suggested). Or I
have to use int.
In the first case I create large code and runtime overhead, in the other
cases I loose any type safety.


Marcel
 
F

Francesco

Let's say I have an observable pattern 'O' in a C API. It calls a
callback function '*cb' with a event type (the enumeration 'A') and a
few other parameters. (I am talking about notifications about
asynchronous changes of information.)

void set_observer(
O obj,
void (*cb)(O obj, A type, void* param),
void* param );

Now I have a C++ application which has objects 'O2' that depend on 'O'
in a way that they add additional features. They are also observables.
But their event type of type 'B' has additional values for changes of
the new features. All events of the base object 'O' are forwarded to the
observers of 'O2' but the observers may receive additional event types.

Now I could map any possibly value of A to a value of B by a large
switch statement or do a hard cast while making implications about the
values of A are defined in B in the same way (as Paavo suggested). Or I
have to use int.
In the first case I create large code and runtime overhead, in the other
cases I loose any type safety.

Thanks for the explanation Marcel.

So if I got it right, you only want to pass enum A to a function which
accepts enum B. Since you said that the first values are the same in
both enums, I suppose you would simply have to build a B from an A, no
need for hard casts or for additional switch statements.

It should work even for the other way round:
(here I've changed it so A is "wider" than B, that should work fine
too)

-------
#include <iostream>
using namespace std;

namespace enA {
enum A { first, second, third, fourth };
}

namespace enB {
enum B { first, second, third };
}

void fun(enB::B b) {
switch (b) {
case enB::first:
cout << "1st";
break;
case enB::second:
cout << "2nd";
break;
case enB::third:
cout << "3rd";
break;
default:
cout << "out-of-range";
}
cout << endl;
}


int main()
{
fun(enB::B(enA::second));
fun(enB::B(enA::fourth));
return 0;
}
-------

Hope that helps, FWIW.

Cheers,
Francesco
 
P

Pascal J. Bourguignon

Marcel Müller said:
Hi,

is there any smart solution for something like sub classes of
enumeration types?

Let's say we have

enum A
{ Value1,
Value2,
Value3
};

enum B
{ Value1,
Value2,
Value3,
Value4,
Value5
};

then enum B can hold all values that A allows and a few more. (Of
course, they cannot exist in the same namespace or class because of
the duplicate names.)
An implicit conversion from A to B is also reasonable. OK, one should
not call this inheritance since the conversion is in the other
direction.

This goes against the Lyskoff Substitution Principle in the case of
return values.


You must ensure that a method in a subclass returns only values that
the superclass may return, otherwise you could not substitute a
subclass for the superclass. Therefore the types defined in
subclasses for return values must be subtypes.

On the other hand, for parameters, you must ensure that a subclass
accepts all the values a superclass may accept. Therefore the types
defined in subclasses for parameters must be supertypes.


class A{
public:
typedef enum { v1,v2,v3, v4,v5,v6 } ResultEnumA;
virtual EnumA getIt(){return v5;}

typedef enum { p1,p2,p3 } ParamEnumA;
virtual void setThat(int p);/* p in ParamEnumA */
// We cannot use a specific enum for the parameter p, since
// subclasses are allowed to take additionnal values.

};

class B:public A{
public:
typedef enum { v1=A::v1,v2=A::v2,v3=A::v3 } ResultEnumB;
virtual EnumA getIt(){return v2;}

typedef enum { p1=A::p1,p2=A::p2,p3=A::p3, p4,p5,p6 ParamEnumB;
virtual void setThat(int p); /* p in ParamEnumB */
};
 

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

Members online

Forum statistics

Threads
473,764
Messages
2,569,566
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top