How to delegate varargs

Bill Baxter dnewsgroup at billbaxter.com
Tue Nov 20 15:05:09 PST 2007


Tomas Lindquist Olsen wrote:
> Sean Kelly wrote:
>> Tomas Lindquist Olsen wrote:
>>> Frank Benoit wrote:
>>>> How can I delegate the variadic argument list to another variadic
>>>>  argument function?
>>>>
>>>> e.g. void myWritef( char[] frm, ... ){ writefln( frm, ??? ); }
>>>>
>>>> And how can I add or remove arguments to these varargs?
>>>
>>> You have to write a "wrapper" function that explicitly takes the 
>>> hidden arguments. In the case of writefln, phobos provides 
>>> OutputStream.writefx.
>>
>> Yup, and this stinks.  I don't suppose some language feature could be
>>  provided for working around this?
>>
>>
>> Sean
> 
> It should be possible, I can't really see anything that could be a
> showstopper. Except using real variadic function to implement it.
> 
> On x86-64 va_list is not a simple pointer to data, so the storage for
> the variadic arguments would have to alloca'd by the caller for this
> idea to work.
> 
> This is exactly what I do in LLVMDC [1] btw, as implementing a variadic
> function is broken on x86-64 (my development platform). Only calling one
> works...
> 
> Ok :) Here's the idea, it's very simple!
> 
> The way it currently works:
> // ---------------------------
> 
> // the function:
> void func(...);
> 
> // really gets the prototype
> void func_impl(TypeInfo[], void*);
> 
> // calling it like this:
> void func(3.0f, "hello"[]);
> 
> // is implemented like this:
> TypeInfo[2] arg_ti = [typeid(float), typeid(char[])];
> struct Tmp { float f, char[] c; }
> Tmp arg_val = Tmp(3.0f, "hello");
> func_impl(arg_ti[], cast(void*)&arg_val);
> 
> // ----------------------------
> 
> Now to be able to pass on the arguments (and possible add to them), we
> need another parameter:
> 
> size_t _argptrLength;
> 
> Further, we also need to be able to pass ... as an argument in a call
> expression.
> 
> // ---------------------------
> 
> // lets implement func2
> void func2(...)
> {
>     // call the first one adding some params
>     func(42, ... , 8.0i);
> }
> 
> // ---------------------------
> 
> // now...
> // the function:
> void func2(...);
> 
> // really gets the prototype
> void func(TypeInfo[], void*, size_t);
> 
> // calling it like this:
> func(42, ...);
> 
> // gets implemented like this:
> TypeInfo[] arg_ti = 
> (cast(TypeInfo*)alloca(TypeInfo.size*(1+_arguments.length)))[0..1+_arguments.length]; 
> 
> 
> arg_ti[0] = typeid(int);
> arg_ti[1..1+arguments.length] = _arguments[];
> 
> void* arg_val = alloca(int.sizeof + _argptrLength);
> *(cast(int*)arg_val) = 42;
> func_impl(arg_ti, arg_val);
> 
> // ----------------------------
> 
> I hope this makes sense, it could be written better, but it should show 
> the idea. All this is stuff the compiler could figure out. Thinking in 
> terms of LLVMDC and codegen, it could be done fairly easily.
> 
> I'm not sure how much work it would be to get the DMD frontend to accept 
> the '...' token as a function argument and generate something meaningful 
> in the AST though.
> 
> Excuse all the LLVMDC references, I know nobody is using it yet (with 
> good reason), but it's my only reference to compiler development :)
> 
> Hope to get some feedback, don't think I've spent this much time on a NG 
> post before :P
> 
> - Tomas Lindquist Olsen
> 
> [1] LLVMDC - LLVM D Compiler - http://www.dsource.org/projects/llvmdc


I don't care how it works, but some clean way to forward function 
varargs that doesn't look like a clumsy afterthought would be fantastic.

--bb



More information about the Digitalmars-d mailing list