Thread overview
How to call function with variable arguments at runtime?
Oct 10, 2017
Mr. Jonse
Oct 10, 2017
bauss
Oct 10, 2017
Marc Schütz
Oct 11, 2017
Mr. Jonse
October 10, 2017
I need to store a hetrogeneous array of delegates. How can I do this but still call the function with the appropriate number of parameters at run time?

I have the parameters as Variant[] params and a function/delegate pointer(void* for now).

Normally I'd push the parameters on the stack and use a call, but I'm sure D has some ability to do this, like apply(foo, args) would be the same as foo(args[0], ..., args[1]).

I'm not concerned about type correctness, it should always be consistent between what I call and what is stored.

Thanks.
October 10, 2017
On Tuesday, 10 October 2017 at 02:58:45 UTC, Mr. Jonse wrote:
> I need to store a hetrogeneous array of delegates. How can I do this but still call the function with the appropriate number of parameters at run time?
>
> I have the parameters as Variant[] params and a function/delegate pointer(void* for now).
>
> Normally I'd push the parameters on the stack and use a call, but I'm sure D has some ability to do this, like apply(foo, args) would be the same as foo(args[0], ..., args[1]).
>
> I'm not concerned about type correctness, it should always be consistent between what I call and what is stored.
>
> Thanks.

Not entirely sure what you're wanting to do, but sounds a lot like variadic parameters.


https://dlang.org/spec/function.html#variadic mixed with some compile-time terminology.
October 10, 2017
On Tuesday, 10 October 2017 at 02:58:45 UTC, Mr. Jonse wrote:
> I need to store a hetrogeneous array of delegates. How can I do this but still call the function with the appropriate number of parameters at run time?
>
> I have the parameters as Variant[] params and a function/delegate pointer(void* for now).
>
> Normally I'd push the parameters on the stack and use a call, but I'm sure D has some ability to do this, like apply(foo, args) would be the same as foo(args[0], ..., args[1]).
>
> I'm not concerned about type correctness, it should always be consistent between what I call and what is stored.
>
> Thanks.

Like so?

import std.variant;

void foo(int a, string b, float c) {
    import std.stdio;
    writefln("a = %s, b = %s, c = %s", a, b, c);
}

auto apply(alias fn)(Variant[] values) {
    import std.traits : ParameterTypeTuple;
    import std.conv : emplace;
    alias Types = ParameterTypeTuple!fn;
    assert(values.length == Types.length);
    Types args = void;
    foreach(i, ref arg; args) {
        // using emplace instead of assignment here to be fully correct
        emplace!(typeof(arg))(&arg, values[i].get!(typeof(arg)));
    }
    return fn(args);
}

void main() {
    Variant[] values = [Variant(1), Variant("Hello world"), Variant(3.14159f)];
    apply!foo(values);
}
October 11, 2017
On Tuesday, 10 October 2017 at 08:26:37 UTC, Marc Schütz wrote:
> On Tuesday, 10 October 2017 at 02:58:45 UTC, Mr. Jonse wrote:
>> I need to store a hetrogeneous array of delegates. How can I do this but still call the function with the appropriate number of parameters at run time?
>>
>> I have the parameters as Variant[] params and a function/delegate pointer(void* for now).
>>
>> Normally I'd push the parameters on the stack and use a call, but I'm sure D has some ability to do this, like apply(foo, args) would be the same as foo(args[0], ..., args[1]).
>>
>> I'm not concerned about type correctness, it should always be consistent between what I call and what is stored.
>>
>> Thanks.
>
> Like so?
>
> import std.variant;
>
> void foo(int a, string b, float c) {
>     import std.stdio;
>     writefln("a = %s, b = %s, c = %s", a, b, c);
> }
>
> auto apply(alias fn)(Variant[] values) {
>     import std.traits : ParameterTypeTuple;
>     import std.conv : emplace;
>     alias Types = ParameterTypeTuple!fn;
>     assert(values.length == Types.length);
>     Types args = void;
>     foreach(i, ref arg; args) {
>         // using emplace instead of assignment here to be fully correct
>         emplace!(typeof(arg))(&arg, values[i].get!(typeof(arg)));
>     }
>     return fn(args);
> }
>
> void main() {
>     Variant[] values = [Variant(1), Variant("Hello world"), Variant(3.14159f)];
>     apply!foo(values);
> }


The problem with this is that the function parameters need to be known. I do not know them. All I have is a function pointer and the arguments in variants.


So, it would work off

void bar(int, string, float) { }


void* foo = &bar;
Variant[] values = [Variant(1), Variant("Hello world"),
Variant(3.14159f)];
apply(foo, values);

So, it has to get the type from the variant at run time and pass the value's appropriately.