Variadic functions: How to pass another variadic function the variadic args?
monarch_dodra
monarchdodra at gmail.com
Sun Aug 4 11:36:56 PDT 2013
On Sunday, 4 August 2013 at 15:29:48 UTC, Ali Çehreli wrote:
> On 08/03/2013 09:05 AM, monarch_dodra wrote:
>
> > On Saturday, 3 August 2013 at 15:10:20 UTC, Ali Çehreli wrote:
> >> On 08/03/2013 07:58 AM, bearophile wrote:
> >>
> >> > Gabi:
> >> >
> >> >> //HOW TO pass F1(..) the args we were called with ?
> >> >
> >> >
> >> > import std.stdio;
> >> >
> >> > void f1(Args...)(Args args) {
> >> > foreach (arg; args)
> >> > arg.writeln;
> >>
> >> Would you expect the following two lines behave the same?
> >>
> >> writeln(args);
> >> writefln("%s", args);
> >
> > I wouldn't.
> >
> >> Apparently not:
> >>
> >> 10hello1.5
> >> 10
> >>
> >> Why?
> >
> > writeln simply prints all the args it receives, then a line
> break.
> >
> > writefln, on the other end, only prints its single "fmt" arg.
> The rest
> > of the args are only used as they are referenced in fmt. Your
> code
> > basically boils down to:
> >
> > writefln("%s", 10, "hello", 1.5);
> > => 10
>
> Does args have a type that makes it a single entity? If so, the
> two should behave the same. For example, the output is the same
> tuples and slices:
>
> import std.stdio;
> import std.typecons;
>
> void foo(Args...)(Args args)
> {
> // Both outputs are the same:
> writeln(tuple(1, "abc", 1.5));
> writefln("%s", tuple(1, "abc", 1.5));
>
> // Both outputs are the same:
> writeln([ 1, 2, 3 ]);
> writefln("%s", [ 1, 2, 3 ]);
>
> // Unfortunately, not here:
> writeln(args);
> writefln("%s", args);
>
> // Let's see why that may be...
>
> // Prints "(int, string, double)"
> writeln(Args.stringof);
> }
>
> void main()
> {
> foo(10, "hello", 1.5);
> }
>
> According to the last line in foo(), args is three types
> together. Is that a TypeTuple I wonder... Yes, it is a
> TypeTuple:
>
> import typetuple;
>
> // ...
>
> // Passes
> static assert(
> is (Args == typeof(TypeTuple!(int.init, string.init,
> double.init))));
>
> Now I see... Since writefln is also a variadic function, it
> naturally peels off the TypeTuple one %s at a time.
>
> It is silly of me to stumble on this :) but I learned that
> there exists one type that is printed differently by the
> following two lines:
>
> writeln(a);
> writefln("%s", a);
>
> Can you think of any other type of 'a' that would be different?
> (Modulo formatting like square brackets around slices, commas
> between elements, etc.)
>
> Ali
Yes, you can build a single "std.typecons.Tuple" out of a
"generic tuple of values". However, this prints because the
*type* "Tuple" is itself printed with all its internals, as
opposed to writefln itself extracting the members of the Tuple.
Any format specifier would be lost, for example.
Note that technically, the type "TypeTuple" doesn't exist. It's a
template that simply forwards "Args". The type itself does not
exist. When you write "TypeTuple!Args", it is immediatly replaced
by "Args" by the compiler. It's only use is that it allows some
syntax that the compiler would not know how to parse without a
bit of help.
For example, if your write "pragma(msg, Args.stringof)", it'll
print:
"(int, string, double)".
As you can see, no TypeTuple. Here, the use of TypeTuple is
obvious though: The code:
"static assert(is(Args == (int, string, double));"
This would not compile, as the compiler would not understand
those tokens. TypeTuple is a simple way of adding grouping,
without confusing the compiler.
Another interesting aspect of TypeTuple (that I found confusing
at first), is that since it is not a type "per se", a TypeTyple
of a TypeTuple is simply the expanded TypeTuple:
TypeTuple!(TypeTuple!(int, string), TypeTuple!(int, string));
is
TypeTuple!(int, string, int, string);
is
(int, string, int, string);
An interesting read which came up recently:
"Variadic grouping"
http://forum.dlang.org/thread/wyokmbxiuetwigbpyumz@forum.dlang.org
Long story short, if you need actual grouping then a plain old:
template Group(Args...)
{
alias Ungroup = Args;
}
or
template Pack(Args...)
{
alias Unpack = Args;
}
Using this will achieve passing several Args as a single grouped
type. However, since it is explicitly packed/grouped, extracting
the actual members will also need to be explicit.
More information about the Digitalmars-d-learn
mailing list