View mode: basic / threaded / horizontal-split · Log in · Help
August 07, 2012
How to create TypeTuple/ExpressionTuple from tuple/tuples
Given e.g. a function template

void f(T ...)(T t) {
  writeln(t.length);
}

How can I call this function with an already-constructed tuple 
but pass the pule as an expressiontuple?

auto v = tuple(1, 2, 3);
f(v);

In the case above, f will print 1 because 1 tuple is given to the 
function, but I want to 'flatten' the tuple before the call, 
making the function see all the values in the tuple and thus 
print 3. I cannot change the function.

Similarly, I want to be able to do this:

auto v0 = tuple(1, 2, 3);
auto v1 = tuple(4, 5, 6);
f(some_function_to_combine_and_flatten_tuples(v0, v1));

And have f print 6.. Calling f(v0, v1) will print 2.

One reason for needing this is that I am using the receive 
function in std.concurrency, and I want to be able to merge 
message handlers from multiple locations.
August 07, 2012
Re: How to create TypeTuple/ExpressionTuple from tuple/tuples
On 8/7/12, "Øivind" <oivind.loe@gmail.com> wrote:
> How can I call this function with an already-constructed tuple
> but pass the pule as an expressiontuple?
>
> auto v = tuple(1, 2, 3);
> f(v);

Use the .expand property:
f(v.expand)
August 07, 2012
Re: How to create TypeTuple/ExpressionTuple from tuple/tuples
On Tuesday, 7 August 2012 at 16:11:05 UTC, Andrej Mitrovic wrote:
> On 8/7/12, "Øivind" <oivind.loe@gmail.com> wrote:
>> How can I call this function with an already-constructed tuple
>> but pass the pule as an expressiontuple?
>>
>> auto v = tuple(1, 2, 3);
>> f(v);
>
> Use the .expand property:
> f(v.expand)

Works like a charm. Thanks!

The last one then becomes f(v0.expand, v1.expand)
August 07, 2012
Re: How to create TypeTuple/ExpressionTuple from tuple/tuples
On 8/7/12, "Øivind" <oivind.loe@gmail.com> wrote:
> The last one then becomes f(v0.expand, v1.expand)

Yeah. It's somewhat possible to use a helper function for multiple
TypeTuples, but the problem is D functions cannot return language
tuples (only TypeTuple from std.typecons which is what the tuple()
call creates) so you would always need to call "expand" before the
function call, e.g.:

void f(T...)(T t)
{
   writeln(t.length);
}

auto expand(T...)(T t)
{
   static if (T.length == 1)
   {
       return t[0];
   }
   else
   static if (T.length > 1)
   {
       return tuple(t[0].expand, expand(t[1..$]).expand);
   }
}

void main()
{
   auto v0 = tuple(1, 2, 3);
   auto v1 = tuple(4, 5, 6);
   auto v2 = tuple(7, 8, 9);

   f(expand(v0, v1, v2).expand);
}

Once D is improved enough to be able to return language tuples this
should be easier to use.
August 07, 2012
Re: How to create TypeTuple/ExpressionTuple from tuple/tuples
On Tue, Aug 7, 2012 at 7:35 PM, Andrej Mitrovic
<andrej.mitrovich@gmail.com> wrote:


> Yeah. It's somewhat possible to use a helper function for multiple
> TypeTuples, but the problem is D functions cannot return language
> tuples (only TypeTuple from std.typecons which is what the tuple()
> call creates) so you would always need to call "expand" before the
> function call, e.g.:

You can also take the 'dual' of your solution and have a template that
makes a function automatically expand tuples:

alias expander!foo efoo;

// efoo is a function that accepts tuples and automatically cracks
them open for you, and then pass them to foo

auto result = efoo(tuple(1,2), "abc", tuple('a', 3.14));
assert(result = foo(1,2,"abc", 'a', 3.14));

The same idea could be use to have a function 'expand' any
user-defined type, be they structs or classes, by applying .tupleof on
them.
The code for expander is a little bit involved, I'm afraid, I had to
use a helper struct.


import std.traits;
import std.typecons;

struct Fill(Expanded...)
{
   Expanded expanded;
   void from(int index = 0, TupleOrNot...)(TupleOrNot args)
   {
       static if (TupleOrNot.length > 0)
       {
           static if (isTuple!(TupleOrNot[0])) // It's a tuple, expand it ...
           {
               expanded[index..index+TupleOrNot[0].length] = args[0].expand;
               from!(index+TupleOrNot[0].length)(args[1..$]); // ...
and continue the recursion
           }
           else // it's not a tuple, let it that way...
           {
               expanded[index] = args[0];
               from!(index+1)(args[1..$]); // ...and continue the recursion
           }
       }
   }
}


/**
Take a function fun and return a transformed function that will expand
std.typecons.Tuple's provided as arguments and let other args untouched
*/
template expander(alias fun) if (isSomeFunction!fun)
{
  ReturnType!fun expander(Args...)(Args args)
  {
       Fill!(ParameterTypeTuple!fun) f; // prepare the future arguments
       f.from(args); // does the expansion job, the arguments are
stored in f.expanded
       return fun(f.expanded);
  }
}

void main()
{
   int foo(int i, double d, string s, char c) { return i + cast(int)d
+ s.length + (c - '0');}
   alias expander!foo efoo;

   writeln( foo(1, 3.14, "abc", 'a') );
   writeln( efoo(tuple(1, 3.14, "abc", 'a')) );
   writeln( efoo(tuple(1, 3.14), "abc", 'a') );
   writeln( efoo(tuple(1, 3.14), tuple("abc", 'a')) );
}
August 07, 2012
Re: How to create TypeTuple/ExpressionTuple from tuple/tuples
On 8/7/12, Philippe Sigaud <philippe.sigaud@gmail.com> wrote:
> You can also take the 'dual' of your solution and have a template that
> makes a function automatically expand tuples

But that doesn't work for variadic templates, which is the OP's case:

int foo(T...)(T t) { return 1; }
alias expander!foo efoo;  // error
August 08, 2012
Re: How to create TypeTuple/ExpressionTuple from tuple/tuples
On Tue, Aug 7, 2012 at 11:31 PM, Andrej Mitrovic
<andrej.mitrovich@gmail.com> wrote:
> On 8/7/12, Philippe Sigaud <philippe.sigaud@gmail.com> wrote:
>> You can also take the 'dual' of your solution and have a template that
>> makes a function automatically expand tuples
>
> But that doesn't work for variadic templates, which is the OP's case:
>
> int foo(T...)(T t) { return 1; }
> alias expander!foo efoo;  // error

The template can easily be modified to deal with template functions,
but in that case, you lose the parameter-type verification, for
example if the function template has a constraint.
August 08, 2012
Re: How to create TypeTuple/ExpressionTuple from tuple/tuples
On Wed, Aug 8, 2012 at 7:01 AM, Philippe Sigaud
<philippe.sigaud@gmail.com> wrote:

>> But that doesn't work for variadic templates, which is the OP's case:
>>
>> int foo(T...)(T t) { return 1; }
>> alias expander!foo efoo;  // error
>
> The template can easily be modified to deal with template functions,
> but in that case, you lose the parameter-type verification, for
> example if the function template has a constraint.

Like this:

/// Helper template to flatten a Tuple
template Expand(T)
{
   static if (isTuple!T)
       alias T.Types Expand;
   else
       alias T Expand;
}

/**
Take a function fun and return a transformed function that will expand
std.typecons.Tuple's provided as arguments and let other args untouched
*/
template expander(alias fun)
{
  auto expander(Args...)(Args args)
  {
       static  if (isSomeFunction!fun)
           alias ParameterTypeTuple!fun Expanded;
       else
           alias staticMap!(Expand, Args) Expanded; // flatten the tuples

       Expanded expanded;
		
       /// Does the filling work: put values extracted from t in expanded
       void from(int index = 0, TupleOrNot...)(TupleOrNot t)
       {
           static if (TupleOrNot.length > 0)
           {
               static if (isTuple!(TupleOrNot[0])) // It's a tuple,
expand it ...
               {
                   expanded[index..index+TupleOrNot[0].length] = t[0].expand;
                   from!(index+TupleOrNot[0].length)(t[1..$]);
               }
               else // it's not a tuple, let it that way...
               {
                   expanded[index] = t[0];
                   from!(index+1)(t[1..$]); // ...and continue the recursion
               }
           }
       }
	
       from(args);
       return fun(expanded);
  }
}

int foo(Ts...)(Ts ts)
{
   return Ts.length;
}
	
void main()
{
  alias expander!foo efoo;

   writeln( foo(1, 3.14, "abc", 'a') );     // 4
   writeln( efoo(tuple(1, 3.14, "abc", 'a')) );      // 4
   writeln( efoo(tuple(1, 3.14), "abc", 'a') );     // 4
   writeln( efoo(tuple(1, 3.14), tuple("abc", 'a')) );     // 4
}
August 08, 2012
Re: How to create TypeTuple/ExpressionTuple from tuple/tuples
On 8/8/12, Philippe Sigaud <philippe.sigaud@gmail.com> wrote:
> Like this..

That's really cool. Could you put this in the DT book, along with your
previous sample? Good job btw!
August 08, 2012
Re: How to create TypeTuple/ExpressionTuple from tuple/tuples
On Wed, Aug 8, 2012 at 7:19 PM, Andrej Mitrovic
<andrej.mitrovich@gmail.com> wrote:
> On 8/8/12, Philippe Sigaud <philippe.sigaud@gmail.com> wrote:
>> Like this..
>
> That's really cool. Could you put this in the DT book, along with your
> previous sample? Good job btw!

Thanks.
Hey, every time I do something like that, you ask me to put it in my
template tutorial ;)
I'm not sure it's *so* useful. Maybe a generic destructuring template,
that opens structs, classes, arrays?
« First   ‹ Prev
1 2
Top | Discussion index | About this forum | D home