Thread overview
Array to argument list
Sep 11, 2008
Simen Haugen
Sep 11, 2008
Sergey Gromov
September 11, 2008
I have an array, but I want to send them one by one to a function that has variadic arguments. Is there a way to do this at runtime?

void p(A ...)(A Args) {}
p([1, 2, 3]); // I want this to become p(1, 2, 3) somehow...
September 11, 2008
On Thu, Sep 11, 2008 at 9:39 AM, Simen Haugen <simen@norstat.no> wrote:
> I have an array, but I want to send them one by one to a function that has variadic arguments. Is there a way to do this at runtime?
>
> void p(A ...)(A Args) {}
> p([1, 2, 3]); // I want this to become p(1, 2, 3) somehow...
>

Hm.  My guess is that in general, "no", since you need to know how many arguments to call p with at compile time, but you don't know how many you'll need until runtime.  You'd have to generate size_t.max instantiations of p to cover all possible array lengths, as well as size_t.max instantiations of a helper function to convert an array into a tuple.

However for a restricted case -- fixed-size arrays -- it's possible. But again, the number of instantiations is proportional to the length of the array.

Here's an ugly, completely un-transparent solution.

import tango.core.Tuple;
import tango.io.Stdout;

struct Tup(T...)
{
    T vals;
}

Tup!(T) makeTup(T...)(T args)
{
    Tup!(T) ret;
    ret.vals = args;
    return ret;
}

template Rep(int num, V...)
{
    static if(num == 0)
        alias Tuple!() Rep;
    else
        alias Tuple!(V[0], Rep!(num - 1, V)) Rep;
}

Tup!(Rep!(N, U)) toTuple(T: U[N], U, int N)(T arr)
{
    Tup!(Rep!(N, U)) ret;

    foreach(i, v; ret.vals)
        ret.vals[i] = arr[i];

    return ret;
}

void p(A...)(A args)
{
    foreach(i, arg; args)
        Stdout.formatln("Arg {}: {}", i, arg);
}

void main()
{
    int[3] arr = [1, 2, 3];
    p(toTuple(arr).vals);
}
September 11, 2008
Simen Haugen <simen@norstat.no> wrote:
> I have an array, but I want to send them one by one to a function that has variadic arguments. Is there a way to do this at runtime?
> 
> void p(A ...)(A Args) {}
> p([1, 2, 3]); // I want this to become p(1, 2, 3) somehow...

With a bit of template trickery I've got this:

> import std.stdio;
> 
> void p(A ...)(A Args) {
>   writeln(A.stringof);
>   writeln(Args[4]);
> }
> 
> void PassArrayAsTuple(alias fun, T: E[S], E, size_t S, R...)(T arr, R rest) {
>   static if (S)
>     PassArrayAsTuple!(fun)(cast(E[S-1])arr, arr[$-1], rest);
>   else
>     fun(rest);
> }
> 
> void main() {
>   PassArrayAsTuple!(p)("array");
> }

Obviously it works only for static arrays.
I wanted to come up with something like

p(ArrayTuple!("array"));

but the trick with casting a static array to a smaller static array does not work for template arguments.  I'm not sure that it should work for function arguments either, bit it works in DMD 2.019 indeed.