July 12, 2013 Re: Style question | ||||
---|---|---|---|---|
| ||||
Posted in reply to Namespace | 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 |
Copyright © 1999-2021 by the D Language Foundation