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