Call C variadic function from D variadic function

ag0aep6g anonymous at example.com
Sun Sep 13 18:35:48 UTC 2020


> ```
>      /// Add a single line to an existing header
>      auto addLine(T...)(RecordType type, T kvargs)
>      if(kvargs.length > 0 && isSomeString!(T[0]))
>      {
>          static assert (kvargs.length %2 == 0);   // K-V pairs => even 
> number of variadic args
> 
>          string varargMagic(size_t len)
>          {
>              string args = "sam_hdr_add_line(this.h, type.ptr, ";
>              for(int i=0; i<len; i++)
>                  args ~= "toStringz(kvargs[" ~ i.to!string ~ "]), ";
>              args ~= "null)";
>              return args;
>          }
> 
>          return mixin(varargMagic(kvargs.length));
>      }
> ```
[...]
> Question:
> If a variadic template, despite presenting to the user a "dynamic 
> array", MUST know its parameter list at compile-time, is there a way 
> (other than with mixins as shown) to pass this parameter list to 
> extern(C) linkage function with variadic parameters?

Easy peasy:

         import std.meta: Repeat;
         Repeat!(kvargs.length, const(char)*) zs;
         foreach (i, ref z; zs) z = toStringz(kvargs[i]);
         return sam_hdr_add_line(this.h, type.ptr, zs, null);

By the way, `kvargs` is not a dynamic array. Its length is not dynamic, 
and it's not an array.

Also, you don't just want to pass the parameters forward. That would be 
trivial: `sam_hdr_add_line(this.h, type.ptr, kvargs, null)`. You want to 
run them through another function first. That's where the difficulty 
comes from.

> (bonus question: if yes, can it be done with typesafe variadic function 
> where I believe parameter list is known at either compile time OR 
> runtime, depending on how called)

I don't see when it would matter how the function is called, but you can 
declare it in two different ways:

1) True typesafe variadic:

     auto addLine(RecordType type, string[] kvargs ...)

2) Template + typesafe variadic:

     auto addLine(size_t n)(RecordType type, string[n] kvargs ...)

In the first one, `kvargs.length` is a dynamic value. You can't use it 
to generate the arguments for a `sam_hdr_add_line` call.

In the second one, `kvargs.length` is a static value. So you can do the 
same things as in the `T...` template. And just like the `T...` 
template, it will generate a new function for every distinct 
`kvargs.length`.


More information about the Digitalmars-d-learn mailing list