Call C variadic function from D variadic function

Paul Backus snarwin at gmail.com
Sun Sep 13 18:35:27 UTC 2020


On Sunday, 13 September 2020 at 17:23:42 UTC, Steven 
Schveighoffer wrote:
> On 9/13/20 12:55 PM, James Blachly wrote:
>> 
>> ```
>>      /// 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));
>>      }
>> ```
>> 
>> Interestingly, compilation fails if the mixin consists only of 
>> the comma-separated parameters ("Comma expression" [1])
>> 
>> 
>> 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?
>
> Was just talking about this exact problem with Adam Ruppe. 
> Unfortunately, because the parameters are an expression tuple, 
> and not a compile-time tuple, you can't use stuff like 
> staticMap.

You actually can, if you define the right kind of helper function:

     /// 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
         immtuable(char)* argToStringz(alias arg)()
         {
             return toStringz(arg);
         }

         return sam_hdr_add_line(this.h, this.ptr, 
staticMap!(argToStringz, kvargs), null);
     }

The clever trick here is that, because of optional parentheses 
[1], `argToStringz!(kvargs[i])` can be interpreted either as the 
name of a function or a function call, depending on the context 
it appears in.

[1] https://dlang.org/spec/function.html#optional-parenthesis


More information about the Digitalmars-d-learn mailing list