In order to do safe varargs, D should have a 'variant' primitive type which
can be anything. When pushing varargs on the stack, a static array of
variants is created, then accessed in the function as an array, using RTTI.
For example:
void printf(...)
{
foreach(variant v; printf.args) {
switch (typeof(v)) {
case typeof(int):
case typeof(string):
}
}
}

In order to do safe varargs, D should have a 'variant' primitive type which
can be anything. When pushing varargs on the stack, a static array of
variants is created, then accessed in the function as an array, using RTTI.
For example:
void printf(...)
{
foreach(variant v; printf.args) {
switch (typeof(v)) {
case typeof(int):
case typeof(string):
}
}
}

If you have to check the type at runtime like that, it's not very
typesafe. ;)
I see two resolutions to this issue. The easy one is the opCall idiom:
stdout.print("aoeuaoeu") (42) (3.141596) ();
The hard (but awesome) one requires some sort of type deduction. Given
that, it would be very simple to add a symbol to the language that
represents "all the other arguments". Normal overloading rules would apply:
void print(char[] s, other) {
puts(s);
print(other);
}
void print(int i, other) {
printf("%i", i);
print(other);
}
void print() {
}
-- andy