www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Template for going from Array --> list of args

reply Bill Baxter <dnewsgroup billbaxter.com> writes:
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
Jan 29 2007
parent reply Kirk McDonald <kirklin.mcdonald gmail.com> writes:
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
Jan 30 2007
parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
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
Jan 30 2007
parent reply Frits van Bommel <fvbommel REMwOVExCAPSs.nl> writes:
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...
Jan 30 2007
parent reply Don Clugston <dac nospam.com.au> writes:
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...).
Jan 31 2007
parent Bill Baxter <dnewsgroup billbaxter.com> writes:
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
Jan 31 2007