Better syntax for varargs / variadic functions?
Bill Baxter
dnewsgroup at billbaxter.com
Wed Oct 4 19:33:00 PDT 2006
The magic _arguments and _argptr really in variadic functions really
bother me.
Why not:
1) let the user name the varargs list like
void foo(int x, Args...)
or
void foo(int x, ...Args)
2) Let _arguments and _argptr simply be fields of that instead of
'magic' variables so:
_arguments --> Args.types
_argptr --> Args.pointers
3) Make it so that users don't have to advance _argptrs themselves.
Make it an array of pointers instead. The compiler knows the types and
their sizes, so there's no reason the user should have to mess with this.
So instead of this :
long j = *cast(long *)_argptr;
_argptr += long.sizeof;
You'd just do:
long j = *cast(long *)_argptr[i];
4) Get rid of the explicit cast. Again the compiler knows the types, so
it seems silly for me to have to explicitly cast the argument myself.
Best would be if it could look like just another array:
long j = *_argvals[i];
But some sort of template call would be ok I suppose
long j = *_argcast!(i);
And of course really this should be a field of the named argument
too. so Args.values[i].
Then we could have this version of the foo example:
void foo(int x, Args...)
{
printf("%d arguments\n", Args.length);
for (int i = 0; i < Args.length; i++)
{ Args.types[i].print();
if (Args.types[i] == typeid(int))
{
int j = Args.values[i];
printf("\t%d\n", j);
}
else if (Args.types[i] == typeid(long))
{
long j = Args.values[i];
printf("\t%lld\n", j);
}
else if (Args.types[i] == typeid(double))
{
double d = Args.values[i];
printf("\t%g\n", d);
}
else if (Args.types[i] == typeid(FOO))
{
FOO f = Args.values[i];
printf("\t%p\n", f);
}
else
assert(0);
}
}
I think 1),2), and 3) are pretty straightforward, I don't see any major
language issues for making those work. Maybe you'll need ...Args
instead of Args... to remain context free, but that'd be acceptable.
The argument against Number 3) may be that building the list of pointers
would mean extra overhead for every varargs-using function. But
generally if an argument is passed in, somebody somewhere down the line
is going to have to compute the address for it. Might as well be the
compiler behind the scenes. The extra storage for those pointers is an
extra overhead, but it seems unlikely to be that much. It's just N
extra pointers that can be put on the stack. And the compiler can even
optimize it out if Args.pointers[i] isn't used in that function.
Number 4) is tricky, though, without making a special case. Generally
somearray[i] can't return values of different types depending on i, so
letting it do so would require that it be treated specially. If there
were someway to cast something to the type represented by a TypeInfo
then you'd be able to use that. But basically the only way to do that
is with a big switch.
Even if 4 is impossible, I think having 1),2 ) and 3) would be nice.
Then foo would look like:
void foo(int x, Args...)
{
printf("%d arguments\n", Args.length);
for (int i = 0; i < Args.length; i++)
{ Args.types[i].print();
if (Args.types[i] == typeid(int))
{
int j = *cast(int*)Args.ptrs[i];
printf("\t%d\n", j);
}
...
Which I still find to be quite an improvement.
But even better would be support for variadic templates which would let
you avoid that 'if type == this {} else if type == that {} else if type
== theother {} ...'. Like here:
http://www.generic-programming.org/~dgregor/cpp/variadic-templates.html
--bb
More information about the Digitalmars-d
mailing list