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