Variadic template arguments unpacking

Artur Skawina art.08.09 at gmail.com
Sun Jul 7 02:46:41 PDT 2013


On 07/06/13 21:39, Max Strakhov wrote:
> 
> If anyine has any ideas how make this implementation simplier, bring it on :)

Well, you could just use the pseudo-code version that you posted,
almost verbatim:

> string res = "";
> for(i, rev v; args)
>     res ~= string.format(", f(args[%d]).val()");
> mixin("return G(" ~ res ~ ");");
> 
> Only without any actual looping and variables, so compiler could deal with it.

   auto F(A...)(string format, A args) {
      mixin({
         string res;
         foreach (I, _; A)
             res ~= (I?", ":"") ~ "conv(args["~I.stringof~"])";
         return "return G(convformat(format), " ~ res ~ ");";
      }());
   }

The compiler can deal with this, no need to make it more complicated.

It's a good idea for non-obvious text-as-code manipulations to be
explicit, so I'd actually do it like that.

A problem when manipulating source code directly is that not
everything can be referred to by name - a non-local type or
symbol which isn't available in the current scope will work when
it's a template parameter or via typeof(), but you can't directly
name it and then mix it back in. Locals, including function args,
will work though. 

For cases where the above restriction isn't a problem, we could
use something more generic, that will make it possible to solve
your problem with a one-liner. It will work with not just
"argument-packs" (ie arg-tuples), but also some symbols, types
and statically evaluable expressions. The "oops" line shows what
does *not* work and why these kinds of mixin tricks should
be used only when you have control over all args and users. 

   template evalExpMap(string C, string F, A...) {
      enum evalExpMap = {
         import std.array;
         string s;
         static if (is(typeof(A))) alias B = typeof(A);
                else               alias B = A;
         foreach (I, _; B)
            s ~= (I?", ":"") ~ replace(F, "%", A[I].stringof);
         return replace(C, "%", s);
      }();
   }
   
   import std.stdio;

   void main() {
       auto c = mixin (evalExpMap!(q{ foo(%) }, q{ getArray(%)[] }, 1, "two", 3.14));
       b1(c, 3_000_000_000u, 2.14, -43L);
       auto s = S!(int, float, "/4", "blah")();
       writeln(typeof(s.data).stringof, typeof(s.blah).stringof);
       //auto oops = S!(typeof(as()), float, "/4", "blah")();
   }

   auto getArray(T)(T n) { T[2] data = n; return data; }

   auto foo(A...)(A args) {
       int c;
       foreach (rs; args) foreach (v; rs) ++c, write(v, " ");
       return c;
   }
   
   void b1(T...)(T values) {
       mixin (evalExpMap!(q{b2('\n',1,2,3,%);}, q{%+1}, values));
   }
   void b2(T...)(T vs) { foreach (v; vs) writeln(v); }
   
   template Q(A...) { alias Q=A; }
   struct S(A...) {
      mixin (evalExpMap!(q{alias T=Q!(%);}, q{%[16]}, A[0..$-2]));
      T data;
      mixin (evalExpMap!(q{Q!(%) }~A[3]~q{;}, q{%[16}~A[$-2]~q{]}, const A[1], shared(A[0])*));
   }
   
   auto as() { struct An {} return An(); }


artur


More information about the Digitalmars-d-learn mailing list