Thread overview
Template for going from Array --> list of args
Jan 30, 2007
Bill Baxter
Jan 30, 2007
Kirk McDonald
Jan 30, 2007
Bill Baxter
Jan 30, 2007
Frits van Bommel
Jan 31, 2007
Don Clugston
Jan 31, 2007
Bill Baxter
January 30, 2007
Is there any better way to do this than what I've got below?
The variadic stuff lets you treat lists of args as arrays, but is there some nice way to go the other direction?  Take the elements of an array and pass them as individual args?

The code below just does a not-so-slick and not-so-exhaustive case-by-case on the number of arguments.  Kind of looks reminiscent of the problems variadic templates are supposed to solve, but I can't figure out any way to use variadics to handle this one.

------
template NArgs(alias func)
{
    static if (is(typeof(func) T == function)) {
        const uint NArgs = T.length;
    }
    else {
        static assert(0, "Not a function with fixed arguments");
    }
}

template callwithN(alias func, alias A) {
    static if (NArgs!(func)==0) {
        void callwithN() {
            func();
        }
    }
    else static if (NArgs!(func)==1) {
        void callwithN() {
            func(A[0]);
        }
    }
    else static if (NArgs!(func)==2) {
        void callwithN() {
            func(A[0], A[1]);
        }
    }
    else static if (NArgs!(func)==3) {
        void callwithN() {
            func(A[0], A[1], A[2]);
        }
    }
    else static if (NArgs!(func)==4) {
        void callwithN() {
            func(A[0], A[1], A[2], A[3]);
        }
    }
    else {
       static assert(0, "Unsupported number of arguments");
    }
}

void foo(int a, int b) { }
void bar(int a, int b, int c) { }

void main()
{
  int[5] a=[0,1,2,3,4];
  callwithN!(foo,a);
  callwithN!(bar,a);
}
-----

What I was thinking was something like:

template callwithN(alias func, alias A) {
        func( array_to_tuple!(NArgs!(func),A) );
        }
    }

but that stalled out because any sort of Tuple!(A[0]) type construct bombs saying that A[0] isn't valid as a template argument.

--bb

January 30, 2007
Bill Baxter wrote:
> Is there any better way to do this than what I've got below?
> The variadic stuff lets you treat lists of args as arrays, but is there some nice way to go the other direction?  Take the elements of an array and pass them as individual args?
> 
> The code below just does a not-so-slick and not-so-exhaustive case-by-case on the number of arguments.  Kind of looks reminiscent of the problems variadic templates are supposed to solve, but I can't figure out any way to use variadics to handle this one.
> 
> ------
> template NArgs(alias func)
> {
>     static if (is(typeof(func) T == function)) {
>         const uint NArgs = T.length;
>     }
>     else {
>         static assert(0, "Not a function with fixed arguments");
>     }
> }
> 
> template callwithN(alias func, alias A) {
>     static if (NArgs!(func)==0) {
>         void callwithN() {
>             func();
>         }
>     }
>     else static if (NArgs!(func)==1) {
>         void callwithN() {
>             func(A[0]);
>         }
>     }
>     else static if (NArgs!(func)==2) {
>         void callwithN() {
>             func(A[0], A[1]);
>         }
>     }
>     else static if (NArgs!(func)==3) {
>         void callwithN() {
>             func(A[0], A[1], A[2]);
>         }
>     }
>     else static if (NArgs!(func)==4) {
>         void callwithN() {
>             func(A[0], A[1], A[2], A[3]);
>         }
>     }
>     else {
>        static assert(0, "Unsupported number of arguments");
>     }
> }
> 
> void foo(int a, int b) { }
> void bar(int a, int b, int c) { }
> 
> void main()
> {
>   int[5] a=[0,1,2,3,4];
>   callwithN!(foo,a);
>   callwithN!(bar,a);
> }
> -----
> 
> What I was thinking was something like:
> 
> template callwithN(alias func, alias A) {
>         func( array_to_tuple!(NArgs!(func),A) );
>         }
>     }
> 
> but that stalled out because any sort of Tuple!(A[0]) type construct bombs saying that A[0] isn't valid as a template argument.
> 
> --bb
> 

Something like this should work (though I haven't tested it):

import std.traits;

void callwith(alias fn, T)(T[] array) {
    ParameterTypeTuple!(typeof(&fn)) t;
    foreach (i, e; t) {
        t[i] = array[i];
    }
    fn(t);
}

void foo(int a, int b) { }

void main() {
    int[5] a = [0,1,2,3,4];
    callwith!(fn, int)(a);
}

-- 
Kirk McDonald
Pyd: Wrapping Python with D
http://pyd.dsource.org
January 30, 2007
Kirk McDonald wrote:
> Bill Baxter wrote:
> 
> Something like this should work (though I haven't tested it):

Works indeed!  Thanks.

> 
> import std.traits;
> 
> void callwith(alias fn, T)(T[] array) {
>     ParameterTypeTuple!(typeof(&fn)) t;

Whoa, didn't realize you could make a variable out of a type tuple.  Or if I did know it once, I completely forgot it.

>     foreach (i, e; t) {
>         t[i] = array[i];
>     }

I guess this squashes any hope of the thing getting inlined... :-(

>     fn(t);
> }
> 
> void foo(int a, int b) { }
> 
> void main() {
>     int[5] a = [0,1,2,3,4];
>     callwith!(fn, int)(a);
> }
> 

--bb
January 30, 2007
Bill Baxter wrote:
> Kirk McDonald wrote:
>>     ParameterTypeTuple!(typeof(&fn)) t;
> 
> Whoa, didn't realize you could make a variable out of a type tuple.  Or if I did know it once, I completely forgot it.
> 
>>     foreach (i, e; t) {
>>         t[i] = array[i];
>>     }
> 
> I guess this squashes any hope of the thing getting inlined... :-(

Are you sure? 'foreach' with a tuple as aggregate is automatically unrolled. Sort of a "static foreach", really. So it's not actually a loop. In fact, the index is a compile-time constant.
I'm not sure how the compiler handles this, but I suspect the optimizer may not even know it used to be any kind of loop at all...
January 31, 2007
Frits van Bommel wrote:
> Bill Baxter wrote:
>> Kirk McDonald wrote:
>>>     ParameterTypeTuple!(typeof(&fn)) t;
>>
>> Whoa, didn't realize you could make a variable out of a type tuple.  Or if I did know it once, I completely forgot it.
>>
>>>     foreach (i, e; t) {
>>>         t[i] = array[i];
>>>     }
>>
>> I guess this squashes any hope of the thing getting inlined... :-(
> 
> Are you sure? 'foreach' with a tuple as aggregate is automatically unrolled. Sort of a "static foreach", really. So it's not actually a loop. In fact, the index is a compile-time constant.
> I'm not sure how the compiler handles this, but I suspect the optimizer may not even know it used to be any kind of loop at all...

I'm almost certain you're right. If inside the loop, you insert asm statements, they are placed after each other, with no indication that the loop ever existed. (Makes it possible to write a compile-time compiler that writes directly to asm code...).
January 31, 2007
Don Clugston wrote:
> Frits van Bommel wrote:
>> Bill Baxter wrote:
>>> Kirk McDonald wrote:
>>>>     ParameterTypeTuple!(typeof(&fn)) t;
>>>
>>> Whoa, didn't realize you could make a variable out of a type tuple.  Or if I did know it once, I completely forgot it.
>>>
>>>>     foreach (i, e; t) {
>>>>         t[i] = array[i];
>>>>     }
>>>
>>> I guess this squashes any hope of the thing getting inlined... :-(
>>
>> Are you sure? 'foreach' with a tuple as aggregate is automatically unrolled. Sort of a "static foreach", really. So it's not actually a loop. In fact, the index is a compile-time constant.
>> I'm not sure how the compiler handles this, but I suspect the optimizer may not even know it used to be any kind of loop at all...
> 
> I'm almost certain you're right. If inside the loop, you insert asm statements, they are placed after each other, with no indication that the loop ever existed. (Makes it possible to write a compile-time compiler that writes directly to asm code...).

Ok.  All's the better then.  Thanks to the three of ya.

--bb