enums and version/static if/"inheritance"
Witold Baryluk
witold.baryluk+d at gmail.com
Sun Aug 4 18:03:02 UTC 2024
On Thursday, 1 August 2024 at 17:46:37 UTC, Walter Bright wrote:
> If you really want conditional enums, you can do this:
>
> ```
> struct E
> {
> enum A = 3;
> enum B = 4;
> version (XYZ) enum C = 5;
> }
>
> E e = E.A;
> ```
```
e2.d:8:7: error: cannot implicitly convert expression ‘A’ of type
‘int’ to ‘E’
8 | E e = E.A;
```
Also fails to catch other issues:
```d
auto e = E.A | 7;
```
Compiles, but I would prefer it didn't in this case.
The closest I was able to get to something decent (using version
in this example is trivial, so only showing inheritance and flag
manipulation) is this example:
```d
struct Typedef(T, T init = T.init, string cookie = "", alias
inherit_from = T) {
private T payload = init;
this(T init) {
payload = init;
}
this(typeof(this) tdef) {
this(tdef.payload);
}
static if (!is(inherit_from : T)) {
this(inherit_from tdef) {
this(tdef.payload);
}
}
auto ref opBinary(string op, this X, B)(auto ref B b) if (op !=
"in") {
return Typedef(mixin("payload "~op~" b.payload"));
}
//static if (!is(inherit_from : T)) {
auto ref opBinaryRight(string op, this X)(auto ref
inherit_from b) {
return Typedef(mixin("b.payload " ~ op ~ " payload"));
}
//}
//auto ref opCast(T, this X)() {
// return cast(T)payload;
//}
}
struct MMap {
alias Flags = Typedef!(ulong, 0, "MMap");
static const Flags None = 0;
static const Flags A = 1;
static const Flags B = 2;
};
struct LinuxMMap {
alias Flags = Typedef!(ulong, 0, "LinuxMMap", MMap.Flags);
static foreach (x; __traits(allMembers, MMap)) {
static if (x != "Flags") {
mixin("static const LinuxMMap.Flags "~x~" = MMap."~x~";");
}
}
static const Flags C = 4;
version (X86_64) {
static const Flags D = 30;
static const Flags E = 34;
} else version (AArch64) {
static const Flags F = 33;
static const Flags G = 36;
} else {
static assert(0);
}
}
auto n(T)(T flags0) {
LinuxMMap.Flags flags = flags0;
import std;
writefln("%s %d", flags, flags.payload);
}
void main() {
n(MMap.A | MMap.B | LinuxMMap.C);
}
```
The "inheritance" part can be easily wrapped in a reusable mixin
template.
It detects (and rejects) constructs like `n(MMap.A | 5)`, etc.
But still accepts `n(5)`, but this is fixable using some template
constraints.
So of course this works, and I knew it even before sending
initial , but it is just quite ugly.
I also did check generate assembly code, and it looks good (all
inlined, and folded to a constant `7` above), at least using gdc.
More information about the Digitalmars-d
mailing list