Strange template problem

Kirk McDonald kirklin.mcdonald at gmail.com
Sat Jul 8 14:10:33 PDT 2006


Kirk McDonald wrote:
> Tom S wrote:
> 
>> Kirk McDonald wrote:
>>
>>> I'm having some trouble with a very odd template problem. Take the 
>>> following code:
>>>
>>> [test.d]
>>> import std.stdio;
>>> import ftype; // Daniel Keep's ftype module
>>>
>>> // A function with default arguments
>>> void foo(int i=20, char[] s="Monkey") {
>>>     writefln("foo: %s %s", i, s);
>>> }
>>>
>>> // A function with the same arguments and no defaults
>>> void bar(int i, char[] s) {
>>>     writefln("bar: %s %s", i, s);
>>> }
>>>
>>> // A function that takes a function pointer and the minimum
>>> // number of arguments the function can be called with, and
>>> // calls it.
>>> void Baz(fn_t, uint MIN_ARGS)(fn_t fn) {
>>>     static if (MIN_ARGS == 0)
>>>         fn();
>>
>>
>>
>> MIN_ARGS is 0 for 'foo', because thats what the NumberOfArgs template 
>> returns, using the function *alias*. the *type* doesnt tell the 
>> compiler that it can be called with no args. thats just a func type 
>> that takes two args. thus the error.
> 
> 
> Then why does it work when I comment out line 28?

Actually, I think I'm going to be really pedantic and correct you:

MIN_ARGS is 0 for 'foo' because I explicitly told it to be (on line 29). 
NumberOfArgs would evaluate to 2, because it does indeed operate on the 
type of the function pointer, which doesn't know a thing about default 
arguments. If lines 28 and 29 instead read:

     Blah!(bar);
     Blah!(foo);

Then it works just fine, calling both functions with two args:

$ ./test
bar: 15 Copper
foo: 15 Copper

But it also works when I comment out line 28 and say "Blah!(foo, 0)", 
which is slightly baffling. Pyd has hitherto relied on this behavior to 
implement its default argument support, and I only recently had this 
issue bite me in the ass.

The following does not work:

void function(int, char[]) fn = &foo;
fn();

And yet, these templates almost seem to trick it into working. Is this a 
compiler check that is preventing possible runtime behavior? (A check 
that my template wackiness has somehow gotten around?)

> 
>>
>>
>>>     else static if (MIN_ARGS == 1)
>>>         fn(10);
>>>     else static if (MIN_ARGS == 2)
>>>         fn(15, "Copper");
>>> }
>>>
>>> // A template function that takes a function alias and the
>>> // minimum number of args it can be called with, and calls
>>> // Baz
>>> void Blah(alias Fn, uint MIN_ARGS = NumberOfArgs!(typeof(&Fn))) () {
>>>     alias typeof(&Fn) fn_t;
>>>     fn_t fn = &Fn;
>>>     Baz!(fn_t, MIN_ARGS)(fn);
>>> }
>>>
>>> void main() {
>>>     Blah!(bar);    // Line 28
>>>     Blah!(foo, 0); // Line 29
>>> }
>>>
>>> $ build test
>>> test.d(14): Error: expected 2 arguments, not 0
>>>
>>> test.d(24): template instance test22.Baz!(void(*)(int i, char[] 
>>> s),0u) error instantiating
>>> test.d(29): template instance test22.Blah!(foo,0) error instantiating
>>>
>>> Curiously, this works if I comment out line 28:
>>>
>>> $ build test
>>> gcc test.o ftype.o -o test -m32 -lphobos -lpthread -lm
>>> $ ./test
>>> foo: 20 Monkey
>>>
>>> It also works if I comment out line 29 instead:
>>>
>>> $ build test
>>> gcc test.o ftype.o -o test -m32 -lphobos -lpthread -lm
>>> $ ./test
>>> bar: 15 Copper
>>>
>>> But if both lines are there together, it fails.
>>>
>>
>>
> 
> 


-- 
Kirk McDonald
Pyd: Wrapping Python with D
http://dsource.org/projects/pyd/wiki



More information about the Digitalmars-d mailing list