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