Style question
Simen Kjaeraas
simen.kjaras at gmail.com
Fri Jul 12 07:27:47 PDT 2013
On 2013-07-11, 20:22, Namespace wrote:
> What should he do?
>
> As far as I can see he has 3 options:
> 1. An external file with the enum information. Both classes would import
> it and could use the same enum. But he cannot change the API, so this is
> no real option.
>
> 2. Change test1 into this:
> ----
> void test1() {
> B b = cast(B) this.a;
> MyStaticClass.test2(b);
> }
> ----
> This works fine. But is it safe? And is it good style?
> And how is this cast converted? Is it cheap?
>
> 3. Change test2 so that it accepts (even) (u)int. But then he lose the
> Type safety.
>
> Does anyone have any advice?
This might be an option:
version (unittest) {
enum A {
foo = 1,
bar = 2,
}
enum B {
foo = 1,
bar = 2,
}
enum C {
foo = 3,
bar = 4,
}
enum D {
baz,
qux,
}
}
template sameMembers(T, U) {
template sameValue(string member) {
enum sameValue = __traits(getMember, T, member) ==
__traits(getMember, U, member);
}
import std.typetuple : allSatisfy;
enum sameMembers =
sameMemberNames!(T,U) &&
allSatisfy!(sameValue, __traits(allMembers, T));
} unittest {
assert(sameMembers!(A,A));
assert(sameMembers!(A,B));
assert(sameMembers!(B,A));
assert(sameMembers!(B,B));
assert(!sameMembers!(A,C));
assert(!sameMembers!(B,C));
assert(!sameMembers!(C,A));
assert(!sameMembers!(C,B));
}
template sameMemberNames(T, U) {
template Has(Type) {
template Has(string member) {
enum Has = __traits(hasMember, Type, member);
}
}
import std.typetuple : allSatisfy;
enum sameMemberNames =
allSatisfy!(Has!T, __traits(allMembers, U)) &&
allSatisfy!(Has!U, __traits(allMembers, T));
} unittest {
assert(sameMemberNames!(A,A));
assert(sameMemberNames!(A,B));
assert(sameMemberNames!(A,C));
assert(sameMemberNames!(B,A));
assert(sameMemberNames!(B,B));
assert(sameMemberNames!(B,C));
assert(sameMemberNames!(C,A));
assert(sameMemberNames!(C,B));
assert(sameMemberNames!(C,C));
assert(sameMemberNames!(D,D));
assert(!sameMemberNames!(A,D));
assert(!sameMemberNames!(B,D));
assert(!sameMemberNames!(C,D));
assert(!sameMemberNames!(D,A));
assert(!sameMemberNames!(D,B));
assert(!sameMemberNames!(D,C));
}
T ConvertEnum(T,U)(U value) if (sameMembers!(T,U)) {
return cast(T)value;
}
T ConvertEnum(T,U)(U value) if (sameMemberNames!(T,U) &&
!sameMembers!(T,U)) {
final switch (value) {
foreach (e; __traits(allMembers, U)) {
case __traits(getMember, U, e):
return __traits(getMember, T, e);
}
}
assert(false);
} unittest {
assert(ConvertEnum!A(B.foo) == A.foo);
assert(ConvertEnum!A(B.bar) == A.bar);
assert(ConvertEnum!A(C.foo) == A.foo);
assert(ConvertEnum!A(C.bar) == A.bar);
assert(ConvertEnum!B(A.foo) == B.foo);
assert(ConvertEnum!B(A.bar) == B.bar);
assert(ConvertEnum!B(C.foo) == B.foo);
assert(ConvertEnum!B(C.bar) == B.bar);
assert(ConvertEnum!C(A.foo) == C.foo);
assert(ConvertEnum!C(A.bar) == C.bar);
assert(ConvertEnum!C(B.foo) == C.foo);
assert(ConvertEnum!C(B.bar) == C.bar);
assert(!__traits(compiles, { auto tmp = ConvertEnum!D(A.foo); }));
assert(!__traits(compiles, { auto tmp = ConvertEnum!D(B.foo); }));
assert(!__traits(compiles, { auto tmp = ConvertEnum!D(C.foo); }));
assert(!__traits(compiles, { auto tmp = ConvertEnum!A(D.foo); }));
assert(!__traits(compiles, { auto tmp = ConvertEnum!B(D.foo); }));
assert(!__traits(compiles, { auto tmp = ConvertEnum!C(D.foo); }));
}
The function ConvertEnum safely converts from one enum to another, given
that the same members exist in both. If the enums are equal (same values
for
each member), a simple cast is used. If the names are equal, but values are
different, a switch/case is built, and A.Foo is converted to B.Foo.
--
Simen
More information about the Digitalmars-d-learn
mailing list