digitalmars.D.learn - How to create TypeTuple/ExpressionTuple from tuple/tuples
- =?UTF-8?B?IsOYaXZpbmQi?= (20/20) Aug 07 2012 Given e.g. a function template
- Andrej Mitrovic (3/7) Aug 07 2012 Use the .expand property:
- =?UTF-8?B?IsOYaXZpbmQi?= (3/11) Aug 07 2012 Works like a charm. Thanks!
- Andrej Mitrovic (31/32) Aug 07 2012 Yeah. It's somewhat possible to use a helper function for multiple
- Philippe Sigaud (61/66) Aug 07 2012 You can also take the 'dual' of your solution and have a template that
- Andrej Mitrovic (4/6) Aug 07 2012 But that doesn't work for variadic templates, which is the OP's case:
- Philippe Sigaud (5/11) Aug 07 2012 The template can easily be modified to deal with template functions,
- Philippe Sigaud (61/68) Aug 07 2012 Like this:
- Andrej Mitrovic (3/4) Aug 08 2012 That's really cool. Could you put this in the DT book, along with your
- Philippe Sigaud (7/11) Aug 08 2012 Thanks.
- Andrej Mitrovic (6/8) Aug 08 2012 Well yeah, we don't want a future Banana(tm) company patenting our
- Philippe Sigaud (5/13) Aug 08 2012 Like the Python Cookbook?
- Kenji Hara (13/21) Aug 08 2012 You can also use slice operator instead of expand property.
- Philippe Sigaud (16/28) Aug 08 2012 I didn't know that.
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.
Aug 07 2012
On 8/7/12, "=D8ivind" <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 =3D tuple(1, 2, 3); f(v);Use the .expand property: f(v.expand)
Aug 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:Works like a charm. Thanks! The last one then becomes f(v0.expand, v1.expand)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)
Aug 07 2012
On 8/7/12, "=D8ivind" <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 =3D=3D 1) { return t[0]; } else static if (T.length > 1) { return tuple(t[0].expand, expand(t[1..$]).expand); } } void main() { auto v0 =3D tuple(1, 2, 3); auto v1 =3D tuple(4, 5, 6); auto v2 =3D 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.
Aug 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')) ); }
Aug 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 tuplesBut 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
Aug 07 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: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.You can also take the 'dual' of your solution and have a template that makes a function automatically expand tuplesBut 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
Aug 07 2012
On Wed, Aug 8, 2012 at 7:01 AM, Philippe Sigaud <philippe.sigaud gmail.com> wrote: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 }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; // errorThe 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.
Aug 07 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!
Aug 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: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?Like this..That's really cool. Could you put this in the DT book, along with your previous sample? Good job btw!
Aug 08 2012
On 8/8/12, Philippe Sigaud <philippe.sigaud gmail.com> wrote:Hey, every time I do something like that, you ask me to put it in my template tutorial ;)Well yeah, we don't want a future Banana(tm) company patenting our codez, we need prior art! :p So maybe it's not book-worthy. Perhaps there should be a github repo with mildly interesting boost-licensed code that anyone can use. Or maybe I'm overthinking it.
Aug 08 2012
On Wed, Aug 8, 2012 at 7:45 PM, Andrej Mitrovic <andrej.mitrovich gmail.com> wrote:On 8/8/12, Philippe Sigaud <philippe.sigaud gmail.com> wrote:Like the Python Cookbook? There was a dsource project like this IIRC, but it was for small modules, not code snippets.Hey, every time I do something like that, you ask me to put it in my template tutorial ;)Well yeah, we don't want a future Banana(tm) company patenting our codez, we need prior art! :p So maybe it's not book-worthy. Perhaps there should be a github repo with mildly interesting boost-licensed code that anyone can use. Or maybe I'm overthinking it.
Aug 08 2012
On Tuesday, 7 August 2012 at 16:11:05 UTC, Andrej Mitrovic wrote:On 8/7/12, "Øivind" <oivind.loe gmail.com> wrote:You can also use slice operator instead of expand property. import std.stdio, std.typecons; void f(T ...)(T t) { writeln(t.length); } void main(){ auto v = tuple(1, 2, 3); f(v[]); // prints 3 auto v0 = tuple(1, 2, 3); auto v1 = tuple(4, 5, 6); f(v0[], v1[]); // prints 6 }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)
Aug 08 2012
On Thu, Aug 9, 2012 at 1:26 AM, Kenji Hara <k.hara.pg gmail.com> wrote:You can also use slice operator instead of expand property.import std.stdio, std.typecons; void f(T ...)(T t) { writeln(t.length); } void main(){ auto v = tuple(1, 2, 3); f(v[]); // prints 3I didn't know that. Nice one. Indeed, it's almost like a range. A bit dangerous, as people might forget that what they get is a tuple with possibly different types, instead of a range, but good to know as it offers a homogeneous syntax. Hey, I have map/filter/reduce functions for tuples, should they be part of Phobos? auto t = tupleMap!(a => to!string(a))(1,'a',"abc'", 3.14); // eager, not lazy assert(t == tuple("1", "a", "abc", "3.14")); auto arr = [t[]]; // crack open & transform into an array assert(is(typeof(arr) == string[])); Of course, the mapping function must be polymorphic or overloaded. The good news is, it may very well have different return types for each argument type, thus giving back another, entirely different tuple. But I'm not sure people use tuples that much in D...auto v0 = tuple(1, 2, 3); auto v1 = tuple(4, 5, 6); f(v0[], v1[]); // prints 6 }
Aug 08 2012