Jump to page: 1 2
Thread overview
How to create TypeTuple/ExpressionTuple from tuple/tuples
Aug 07, 2012
Øivind
Aug 07, 2012
Andrej Mitrovic
Aug 07, 2012
Øivind
Aug 07, 2012
Andrej Mitrovic
Aug 07, 2012
Philippe Sigaud
Aug 07, 2012
Andrej Mitrovic
Aug 08, 2012
Philippe Sigaud
Aug 08, 2012
Philippe Sigaud
Aug 08, 2012
Andrej Mitrovic
Aug 08, 2012
Philippe Sigaud
Aug 08, 2012
Andrej Mitrovic
Aug 08, 2012
Philippe Sigaud
Aug 08, 2012
Kenji Hara
Aug 09, 2012
Philippe Sigaud
August 07, 2012
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
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
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
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
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
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
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
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
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
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