Problem with templates

Jarrett Billingsley kb3ctd2 at yahoo.com
Mon Jul 7 08:32:55 PDT 2008


"Sean Reque" <seanthenewt at yahoo.com> wrote in message 
news:g4tbqt$2g8k$1 at digitalmars.com...
> Could someone help me understand why this function doesn't work?
>
> R delegate(T) my_compose(R, IR, IT, T...)(IR delegate(T) first, R 
> delegate(IT) second) {
>  return delegate(T args) { second(first(args)); };
> }
>
> I attempt to invoke the function like this:
>
>  my_compose(&SQLAllocHandle, &SQL)(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &env);
>
> where SQLAllocHandle is a C function that returns a short and SQL is a 
> function that accepts a short as its only parameter. I get the following 
> error:
>
> test.d(35): template test.my_compose(R,IR,IT,T...) does not match any 
> function template declaration
> test.d(35): template test.my_compose(R,IR,IT,T...) cannot deduce template 
> function from argument types !()(shortC  function(short, void*, 
> void**),void function(short rc))
> test.d(35): Error: function expected before (), not 
> (my_compose(R,IR,IT,T...))((& SQLAllocHandle),(& SQL)) of type int
>
>
> I am using two separate template types, IR and IT, because according to 
> the error message function 1 returns a shortC and function two accepts a 
> short. I assume a shortC is implicitly convertible to a short :). I am 
> guessing the shortC comes from the fact that SQLAllocHandle is an 
> extern(C) function.
>
> I tried to model this function off of the Curry example in d 2.0 on this 
> page: http://digitalmars.com/d/2.0/template.html. I am using version 
> 2.015. I really don't understand how what I am doing is any different 
> conceptually than this curry example, which works fine.
>
>

"shortC" is not a type, it's just the compiler outputting the type of the 
function stupidly.  It probably should read something like "extern(C) short 
function(short, void*, void**)".

Even if your template did work, unless you're using D2, it will fail 
spectacularly at runtime since you're returning a delegate, and when you try 
to call said delegate it will simply give garbage or crash the program as it 
is trying to access the 'first' and 'second' locals off the stack which no 
longer exist.

I tried compiling your code just using some D functions and ran into two 
issues:

1. The delegate that you return doesn't return anything.  It should be 
"return second(first(args));" but that's probably just a typo.

2. The compiler ICEs once that's fixed.  If the T parameter is changed to a 
non-tuple, it "works" (but again, in D1 the resulting delegate is invalid 
and gives garbage).

Another way to implement compose involves creating a static function, which 
will probably be a bit faster too.

import tango.io.Stdout;
import tango.core.Traits;

ReturnTypeOf!(f2) compose(alias f1, alias f2)(ParameterTupleOf!(f1) p)
{
    return f2(f1(p));
}

void main(char[][] args)
{
    int foo(double x) { return cast(int)x; }
    int bar(int x) { return x * x; }

    Stdout.formatln("{}", compose!(foo, bar)(4.5));
}

This should also work with C functions, no problem.

If you're using Phobos, you'd instead import std.traits, use "ReturnType" 
instead of "ReturnTypeOf", and "ParameterTypeTuple" instead of 
"ParameterTupleOf". 




More information about the Digitalmars-d-learn mailing list