V
Vaclav Haisman
Motivation:
I have been working on some project recently that uses lots of enums with
disjunctive intervals of values because it is rather convenient way to
define series of constants with consecutive values. The problem is that some
functions should only accept some of the ranges. To store values of more
than one range/enum in variable one has to use int as storage which imho
compromises type safety because any function that wants to accept such
union/range has to use int as paramter to pass these values. Thinking about
this led me to "enum aggregation" which would basically would be this:
Syntax
Enum AB has all enumerators from A and B with their respective values and it
adds its two enumerators to the set. Values of AB's own enumerators start at
max(A,B)+1 unless specified otherwise.
enum A {E1, E2};
enum B {E3, E4};
enum AB : A, B {E5, E6};
// AAB and ABB are different types but they have same range of values.
enum AAB : A, A, B {};
enum ABB : A, B, B {};
enum C : A {E1 = 1}; // Ill-formed, redefinition of E1 from enum
A1.Assignments
A a;
B b;
AB c;
// Ordinary assignment to variable of enum A type.
a = E1;
// Assignment of from base enum. Should work. Implicit cast to derived type.
c = a;
// Assignment from derived enum to base.
a = static_cast<A>(c); // Ok with cast.
b = c; // Ill-formed, requires cast.Overloading resolution
Enumerators always have type of the enum in that they are declared.
void f (A a); // 1
void f (B b); // 2
void f (AB ab); // 3
void g (AAB);
void g (ABB);
f (a); // Calls 1 as the types match exactly.
f (c); // Calls 3 as the types match exactly too.
f (E3); // Calls 2 because E3 is defined in enum B.
f (static_cast<AB>(E3)); // Calls 3.
g (E1); // ill-formed, ambiguous resolution.Templates
Deduction
Because enumerators and variables have exact type, no ambiguities, template
parameter deduction should always deduce correct types. Unless of course
pathological case as with function g() appears.
Vaclav Haisman
PS: While I was witing this post it has occurred to me that solving this
problem using Ada-like subtypes isn't bad idea either.
I have been working on some project recently that uses lots of enums with
disjunctive intervals of values because it is rather convenient way to
define series of constants with consecutive values. The problem is that some
functions should only accept some of the ranges. To store values of more
than one range/enum in variable one has to use int as storage which imho
compromises type safety because any function that wants to accept such
union/range has to use int as paramter to pass these values. Thinking about
this led me to "enum aggregation" which would basically would be this:
Syntax
Enum AB has all enumerators from A and B with their respective values and it
adds its two enumerators to the set. Values of AB's own enumerators start at
max(A,B)+1 unless specified otherwise.
enum A {E1, E2};
enum B {E3, E4};
enum AB : A, B {E5, E6};
// AAB and ABB are different types but they have same range of values.
enum AAB : A, A, B {};
enum ABB : A, B, B {};
enum C : A {E1 = 1}; // Ill-formed, redefinition of E1 from enum
A1.Assignments
A a;
B b;
AB c;
// Ordinary assignment to variable of enum A type.
a = E1;
// Assignment of from base enum. Should work. Implicit cast to derived type.
c = a;
// Assignment from derived enum to base.
a = static_cast<A>(c); // Ok with cast.
b = c; // Ill-formed, requires cast.Overloading resolution
Enumerators always have type of the enum in that they are declared.
void f (A a); // 1
void f (B b); // 2
void f (AB ab); // 3
void g (AAB);
void g (ABB);
f (a); // Calls 1 as the types match exactly.
f (c); // Calls 3 as the types match exactly too.
f (E3); // Calls 2 because E3 is defined in enum B.
f (static_cast<AB>(E3)); // Calls 3.
g (E1); // ill-formed, ambiguous resolution.Templates
Deduction
Because enumerators and variables have exact type, no ambiguities, template
parameter deduction should always deduce correct types. Unless of course
pathological case as with function g() appears.
Vaclav Haisman
PS: While I was witing this post it has occurred to me that solving this
problem using Ada-like subtypes isn't bad idea either.