On Tue, Apr 24, 2012 at 08:03:07PM +0200, Timon Gehr wrote:
> On 04/24/2012 07:37 PM, H. S. Teoh wrote:
> >I'm trying to write a template function for doing member-wise
> >comparisons between two objects, with an optional list of members to
> >ignore. But I can't seem to figure out the syntax for passing a list of
> >strings (or an AA of strings) to the function?
> >
> >I tried this:
> >
> >     bool compareByMemb(string[] ignores, T)(T obj1, T obj2) {
> >             foreach (name; __traits(getAllMembers, T)) {
> >                     ...
> >             }
> >     }
> >
> >but the compiler complains:
> >
> >     Error: arithmetic/string type expected for value-parameter, not string[]
[...]
> Try using an alias parameter (with an optional type constraint). imo
> the template instantiation semantics needs a clean-up.

Thanks, that did it!

For posterity, here's the code (which I think is generally usable for
many more things than I'm using it for in my code):

        bool membCmp(T)(T t1, T t2) {
                return membCmpIgnoring!(cast(string[])[])(t1, t2);
        }

        bool membCmpIgnoring(alias ignores, T)(T t1, T t2)
                if (is(typeof(ignores)==string[]))
        {
                nextMemb: foreach (name; __traits(allMembers, T)) {
                        foreach (i; ignores) {
                                if (name == i)
                                        continue nextMemb;
                        }
                        static if (__traits(compiles, &__traits(getMember, t1,
                                                                name)))
                        {
                                alias typeof(__traits(getMember, t1, name))
                                        type;
                                static if (!is(type==function))
                                {
                                        auto val1 = __traits(getMember, t1, 
name);
                                        auto val2 = __traits(getMember, t2, 
name);
                                        if (val1 != val2)
                                                return false;
                                }
                        }
                }
                return true;
        }

Given two structs or objects, X and Y, this lets you do an easy
implementation of opEquals():

        bool opEquals(Object obj) {
                auto o = cast(typeof(this))obj;
                return obj && membCmp(this, o);
        }

If you wish to ignore some fields, say x and y, in the comparison, then
just do this:

        bool opEquals(Object obj) {
                auto o = cast(typeof(this))obj;
                return obj && membCmpIgnoring!(["x", "y"])(this, o);
        }


Question: is it possible to sugar up the syntax even more, by allowing
an array of aliases? Or is that pushing the template syntax a bit too
far? I.e., can we make it possible to write:

        membCmpIgnoring!(x,y)(this, o)

without the string list syntax?


T

-- 
Prosperity breeds contempt, and poverty breeds consent. -- Suck.com

Reply via email to