creating a variadic interface

Artur Skawina art.08.09 at gmail.com
Mon Jul 8 06:01:15 PDT 2013


On 07/08/13 13:25, JS wrote:
> mixin template a(T...)
> {
>     template b(TT...)
>     {
>         static string eval()
>         {
>             string s;
>             int i = 0;
>             foreach(t; TT)
>                 s = "@property "~(t).stringof~" Name"~to!string(i++)~"();\n";
>             return s;
>         }
>         enum b = eval();
>     }
> 
>     mixin("mixin(b!T);");
>     
> }

It won't work if one of the types isn't already available inside the
template - the .stringof will give you the name, but the mixin
will fail; to avoid this you can use `T[0]` etc as the type directly,
w/o stringifying.

Something like this would also work:

   template evalExpMap(string C, string F, A...) {
      enum evalExpMap = {
         import std.array, std.conv;
         string s, l;
         static if (is(typeof(A))) alias B = typeof(A);
                else               alias B = A;
         foreach (I, _; B) {
            auto r = replace( replace(F, "%s", A[I].stringof),
                                         "%d", to!string(I));
            l ~= (I?", ":"") ~ r;
            s ~=               r ~ ";\n";
         }
         return replace(replace(C, "%...;", s), "%...", l);
      }();
   }

   interface A(T, S...) {
      mixin(evalExpMap!(q{%...;}, q{@property S[%d]/*%s*/ property%d()}, S));
   }

   class C : A!(int, long, string) { /* Needs `propertyN` implementations. */ }


It expands to:

   interface A(T, S...) {   
      @property S[0]/*long*/ property0();
      @property S[1]/*string*/ property1();
   }

and is more readable (once one knows what that helper does ;) ).

In real code, the property names may need to be more configurable;
but I'm not sure what you want to use this for. The helper rewrites
every "%s" pattern -> type-name and every "%d" -> index; maybe that
is enough.

artur


More information about the Digitalmars-d-learn mailing list