Template instantiation and overloaded functions
Daniel Keep
daniel.keep.lists at gmail.com
Sun Mar 25 15:27:03 PDT 2007
Falk Henrich wrote:
> Hi,
>
> I'm troubled by D's template instantiation algorithm in combination with
> overloaded functions. If I have
>
> Z[] zip(X,Y,Z)(Z function(X, Y) f, X[] x, Y[] y)
> { Z[] z; z.length = x.length;
> for(size_t i = 0; i < x.length; i++) { z[i] = f(x[i], y[i]); }
> return z;
> }
>
> and some functions
>
> double plus(double x, double y) {return x+y;}
> long plus(long x, long y) {return x+y;}
> int plus(int x, int y) {return x+y;}
>
> and now do
>
> int[] a = [1,2,0]; int[] b = [0,1,0];
> writefln(zip(&plus, a,b));
>
> the compiler (gdc 0.23) tells me:
>
> functional.d:186: template functional.zip(X,Y,Z) does not match any template
> declaration
> functional.d:186: template functional.zip(X,Y,Z) cannot deduce template
> function from argument types (double(*)(double x, double y),int[],int[])
>
> By switching the order of declaration of the overloaded plus functions I
> discovered that the compiler will only consider the first declaration, no
> matter what. Does this behavior adhere to the D specification?
>
> Falk
As far as I understand it, the problem is that there's no way to
directly specify which overload of a method you want. I believe there
was a trick involving casting the pointer, but I never really used it :P
I think what's happening here is that when you specify &plus, since it's
overloaded, it takes the first one it finds. It then grabs a and b, and
then tries to instantiate the template.
Problem is that the first argument is a double(*)(double,double), but
the template parameters say that it's supposed to be... well, it doesn't
actually say, really. But it's the wrong one, at any rate :P
One solution is to put your operator functions in a template, and always
access them explicitly, like so:
> T plus(T)(T a, T b) { return a + b; }
>
> zip(&plus!(int), a, b);
Another solution, which is a bit more hacky, would be to overload the
zip function with a second version that looks like this:
> tZipResult!(fn, X, Y)[] zip(alias fn, X, Y)(X[] a, Y[] b)
> {
> // ...
> }
And use that casting trick I mentioned earlier to derive the 'Z' type,
and get the function overload you actually want. So to the user, it
would look like this:
> zip!(plus)(a, b);
Incidentally, I never wrote a 'zip' function because you can't return
tuples from functions yet[1]. :P Yours looks more like two-argument
map... n-argument map should be possible using variadic templates (so
long as the collection types aren't iterators, in which case you're
screwed), I just never got around to doing it. :P
In any case, a few people have suggested a number of times that it be
possible to pick out one particular instance of an overload, but no nice
way of doing it has actually emerged. :(
-- Daniel
[1] *And* because, as far as I know, there's no way to iterate over
multiple iterators at once without bringing some form of threading into
the mix. Ick.
--
int getRandomNumber()
{
return 4; // chosen by fair dice roll.
// guaranteed to be random.
}
http://xkcd.com/
v2sw5+8Yhw5ln4+5pr6OFPma8u6+7Lw4Tm6+7l6+7D
i28a2Xs3MSr2e4/6+7t4TNSMb6HTOp5en5g6RAHCP http://hackerkey.com/
More information about the Digitalmars-d-learn
mailing list