Merging two named Tuples

anonymous via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Thu Oct 29 12:42:09 PDT 2015


On 29.10.2015 19:59, Edwin van Leeuwen wrote:
> On Saturday, 24 October 2015 at 11:04:14 UTC, Edwin van Leeuwen wrote:
>> I am trying to write a function to merge two named structs, but am
>> completely stuck on how to do that and was wondering if anyone good
>> provide any help. I know I can access the different names with
>> tup.fieldNames, but basically can't work out how to use that to build
>> the new return type. Below is an outline of what I am trying to do
>> (with unittest). Any pointers would be greatly appreciated.
>
> I tried the following, but get a compile error:
> source/ggplotd/aes.d(633): Error: variable tup cannot be read at compile
> time
> source/ggplotd/aes.d(633): Error: argument to mixin must be a string,
> not (__error)
> source/ggplotd/aes.d(646): Error: template instance
> ggplotd.aes.merge!(Tuple!(string[], "x", string[], "y", string[],
> "label"), Tuple!(double[], "x", double[], "y")) error instantiating
>
> import std.typecons : Tuple;
> template merge(T, U)
> {
>      auto merge( T base, U other )
>      {
>          string typing = "Tuple!(";
>          string variables = "(";
>          foreach( i, t; other.fieldNames )
>          {
>              typing ~= other.Types[i].stringof ~ ",\"" ~ t ~ "\",";
>              variables ~= "other." ~ t ~ ",";
>          }
>
>          foreach( i, t; base.fieldNames )
>          {
>              bool contains = false;
>              foreach( _, t2; other.fieldNames )
>              {
>                  if (t==t2)
>                      contains = true;
>              }
>              if (!contains)
>              {
>                  typing ~= base.Types[i].stringof ~ ",\"" ~ t ~ "\",";
>                  variables ~= "base." ~ t ~ ",";
>              }
>          }
>          string tup = typing[0..$-1] ~ ")" ~ variables[0..$-1] ~ ");";
>          // Do some clever CTFE
>          return mixin(tup);
>      }
> }
>
> ///
> unittest
> {
>      auto xs = ["a","b"];
>      auto ys = ["c","d"];
>      auto labels = ["e","f"];
>      auto aes = Tuple!(string[], "x", string[], "y", string[], "label")(
>              xs, ys, labels );
>
>      auto nlAes = merge( aes, Tuple!(double[], "x",
>                  double[], "y" )(
>                  [0,1], [3,4] ) );
>
>      assertEqual( nlAes.x[0], 0 );
>      assertEqual( nlAes.label.front, "e" );
> }
>
> I guess fieldNames does not exist at compile time? Can I get the
> fieldNames etc at compile time?
>
> Cheers, Edwin

`tup` is an ordinary (run time, dynamic) string to the type system. You 
can't mixin those. You can only mixin static values (enum, static 
immutable, CTFE results).

The code you're generating doesn't depend on `base` and `other`. All it 
needs are `T` and `U`. So, you can generate the code from the types and 
mix it into a function that takes `T base, U other`:

----
template merge(T, U)
{
     auto generateCode()
     {
         string typing = "Tuple!(";
         string variables = "(";
         foreach( i, t; U.fieldNames )
         {
             typing ~= U.Types[i].stringof ~ ",\"" ~ t ~ "\",";
             variables ~= "other." ~ t ~ ",";
         }

         foreach( i, t; T.fieldNames )
         {
             bool contains = false;
             foreach( _, t2; U.fieldNames )
             {
                 if (t==t2)
                     contains = true;
             }
             if (!contains)
             {
                 typing ~= T.Types[i].stringof ~ ",\"" ~ t ~ "\",";
                 variables ~= "base." ~ t ~ ",";
             }
         }
         return "return " ~ typing[0..$-1] ~ ")" ~ variables[0..$-1] ~ ");";
     }

     auto merge(T base, U other)
     {
         mixin(generateCode());
     }
}
----


More information about the Digitalmars-d-learn mailing list