I hacked together something nasty, but which sort of works and allows use of enum values that aren't contiguous powers-of-2.
The following is the 'enum' definition, with the actual enum values being defined in the DEFINE_MYENUM(x,y) statements:
#include <cmath>
#include <map>
class Value {
public:
virtual operator int() const = 0;
int getIndex() const { return index; }
static const Value& fromValue(int val)
{
return *(getReverseMap().find(val)->second);
}
protected:
int index;
static int getNextIndex() {
static int curIndex = 0;
return curIndex++;
}
static std::map<int, Value*>& getReverseMap() {
static std::map<int, Value*> reverseMap = std::map<int, Value*>();
return reverseMap;
}
};
template<int y> class ValueImpl : Value {
public:
ValueImpl() {
index = Value::getNextIndex();
Value::getReverseMap()[y] = this;
}
virtual operator int() const override { return y; }
};
#define DEFINE_MYENUM(NAME, VALUE) const ValueImpl<VALUE> NAME
class MyEnumDefs {
public:
DEFINE_MYENUM(Value1, 2);
DEFINE_MYENUM(Value2, 4);
DEFINE_MYENUM(Value3, 8);
DEFINE_MYENUM(Value4, 16);
DEFINE_MYENUM(Value5, 20);
DEFINE_MYENUM(Value6, 25);
int distance(const Value& x, const Value& y) {
return std::abs(x.getIndex() - y.getIndex());
}
int distance(int x, int y) {
const Value& xx = Value::fromValue(x);
const Value& yy = Value::fromValue(y);
return distance(xx, yy);
}
};
#undef DEFINE_MYENUM
class MyEnum {
public:
static MyEnumDefs& inst() {
static MyEnumDefs internalInst = MyEnumDefs();
return internalInst;
}
};
#define MyEnum MyEnum::inst()
The following is the test code:
int main(int argc, const char * argv[])
{
int a = MyEnum.Value1;
int b = MyEnum.Value2;
int c = MyEnum.Value3;
int d = MyEnum.Value4;
int e = MyEnum.Value5;
int f = MyEnum.Value6;
printf("a b c d e f: %d %d %d %d %d %d\n", a, b, c, d, e, f);
printf("Distance b d: %d\n", MyEnum.distance(b, d));
printf("Distance d b: %d\n", MyEnum.distance(d, b));
printf("Distance e f: %d\n", MyEnum.distance(e, f));
return 0;
}
Output:
a b c d e f: 2 4 8 16 20 25
Distance b d: 2
Distance d b: 2
Distance e f: 1
Obviously this is not perfect, e.g. syntax MyEnum.XXX instead of XXX or MyEnum::XXX, lack of ability to use 'MyEnum' as a type etc... but figured it's a good start on something that could be pretty neat :)