TDPL: Overloading template functions

Philippe Sigaud philippe.sigaud at gmail.com
Fri Jul 30 15:04:22 PDT 2010


First,  trying a copy-paste of your code gives me an error in object.di
(DMD 2.047 on Windows)

C:\dmd\windows\bin\..\..\src\druntime\import\object.di|487|Error:
incompatible types for ((a) != (a2[i])): 'string' and 'immutable(char)'|
||=== Build finished: 1 errors, 0 warnings ===|

And Code::Blocks jumps me to object.di:

bool _ArrayEq(T1, T2)(T1[] a1, T2[] a2)
{
    if (a1.length != a2.length)
return false;
    foreach(i, a; a1)
    { if (a != a2[i]) // <-- line 487. Uh oh, trying to compare strings and
chars
    return false;
    }
    return true;
}

I had to modify it:

bool _ArrayEq(T1, T2)(T1[] a1, T2[] a2)
if (is(typeof(T1.init != T2.init))) // Are T1 and T2 comparable? If not, do
not bother to compile
{
   if (a1.length != a2.length) return false;
    foreach(i, a; a1)
    { if (a != a2[i])
        return false;
    }
    return true;
}

Another possibility would have it return false, but in that case, array
comparisons always compile and we lose the ability to use them as test for
instantiating a template.

I guess _ArrayEq is some internal called by the constraint, while doing the
comparison. Saving object.di and recompiling everything allows the templates
constraints to function and gives me a call to the first find.

Without the '&& false', it still calls the first find... because it still
cannot instantiate the second template:

The first find can be instantiated with T = immutable(char)[] and E =
immutable(char)[], there is nothing stopping it: T and E are the same type,
so they are trivially comparable. "two" is a valid target value for ["one",
"two"].
The second find would have T1 = immutable(char)[] and T2 = immutable(char)
and those do not compare.


testing it, find("one two three", "two") correctly calls the second version
and returns "two three".

So, maybe you just found a bug in object.di._ArrayEq. I'll post on the main
list. Anyway, for me, it seems to work, if I understand correctly what
you're doing.

Btw, if you find yourself using the same constraint regularly, you can
abstract it away in another template that returns (er, becomes, rather) a
boolean:

template areComparable(T1, T2)
{
   enum bool areComparable = is(typeof(T1.init == T2.init)); // eponymous
template trick
}

And then:

T[] find(T, E)(T[] haystack, E needle)
    if (areComparable!(T, E))
{
}


T[] find(T, E)(T[] longer, E[] shorter)
    if (areComparable!(T, E))

{
}

Which makes for cleaner code. I renamed T1 and T2 to T and E, so showcase
the difference between the two.


Philippe
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.puremagic.com/pipermail/digitalmars-d/attachments/20100731/3e65ca86/attachment-0001.html>


More information about the Digitalmars-d mailing list