Call C variadic function from D variadic function

Steven Schveighoffer schveiguy at gmail.com
Sun Sep 13 19:16:48 UTC 2020


On 9/13/20 2:35 PM, Paul Backus wrote:
> 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.

That's cool. And horrific at the same time :) I mean the templates that 
you have to instantiate for this...

I would prefer the mixin solution, even though it's uglier. I think 
something that abstracts that out would be a nice thing to have for 
std.meta.

-Steve


More information about the Digitalmars-d-learn mailing list