www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Variadic Tuple of Structs with Mixed Types

reply jmh530 <john.michael.hall gmail.com> writes:
I'm trying to create a tuple of variadic length containing 
structs with mixed types. So for instance, given

struct Foo(T, U)
{
	T x;
	U y;
}

I want to create something like
Tuple!(Foo!(type1, type2), Foo!(type1, type3), ..., Foo!(type1, 
typeN)) x;

The bar function (below) is what I've tried to use to create it.

template bar(T, U...)
	if (U.length > 1)
{
	
	import std.meta : staticMap;
	
	template baz(A)
	{
		import std.meta : AliasSeq;
		
		alias baz = AliasSeq!(T, A);
	}
	
	alias V = staticMap!(baz, U);
	alias bar = staticMap!(Foo, V);
}

void main()
{
	import std.typecons : Tuple;

	Tuple!(bar!(int, float, int)) x;
}

My strategy was getting something like
AliasSeq!(AliasSeq!(type1, type2), AliasSeq!(type1, type3), ... )
and then I can staticMap over that with Foo in order to create 
the correct type.

However, I can't seem to get it working.

Any ideas?
Jul 08 2016
parent reply ag0aep6g <anonymous example.com> writes:
On 07/09/2016 12:33 AM, jmh530 wrote:
 I'm trying to create a tuple of variadic length containing structs with
 mixed types. So for instance, given

 struct Foo(T, U)
 {
      T x;
      U y;
 }

 I want to create something like
 Tuple!(Foo!(type1, type2), Foo!(type1, type3), ..., Foo!(type1, typeN)) x;

 The bar function (below) is what I've tried to use to create it.

 template bar(T, U...)
      if (U.length > 1)
 {

      import std.meta : staticMap;

      template baz(A)
      {
          import std.meta : AliasSeq;

          alias baz = AliasSeq!(T, A);
      }

      alias V = staticMap!(baz, U);
      alias bar = staticMap!(Foo, V);
 }

 void main()
 {
      import std.typecons : Tuple;

      Tuple!(bar!(int, float, int)) x;
 }

 My strategy was getting something like
 AliasSeq!(AliasSeq!(type1, type2), AliasSeq!(type1, type3), ... )
 and then I can staticMap over that with Foo in order to create the
 correct type.

 However, I can't seem to get it working.

 Any ideas?
AliasSeq expands automatically. That means, AliasSeq!(AliasSeq!(type1, type2), AliasSeq!(type1, type3)) is the same as AliasSeq!(type1, type2, type1, type3) You can see this in action with `pragma(msg, V);` which prints "(int, float, int, int)". Obviously, the next staticMap fails then, because it gets handed a list of individual types, but it should operate on pairs of types. You need to wrap your pairs in something stronger than AliasSeq. You can use a std.typecons.Tuple or a little custom template. Then you need to unwrap it before applying Foo, because Foo works on a pair of types not a Tuple or custom wrapper. Putting it together: ---- template bar(T, U...) if (U.length > 1) { import std.meta : staticMap; import std.typecons : Tuple; alias baz(A) = Tuple!(T, A); alias V = staticMap!(baz, U); alias TupleToFoo(T : Tuple!(Types), Types ...) = Foo!Types; // Alternative TupleToFoo with less complex syntax: // alias TupleToFoo(T) = Foo!(T.Types); alias bar = staticMap!(TupleToFoo, V); } ---- Or with a more lightweight, custom wrapper: ---- template bar(T, U...) if (U.length > 1) { import std.meta : staticMap; template Box(stuff ...) { alias contents = stuff; } alias baz(A) = Box!(T, A); alias V = staticMap!(baz, U); alias BoxToFoo(alias box) = Foo!(box.contents); alias bar = staticMap!(BoxToFoo, V); } ----
Jul 08 2016
next sibling parent jmh530 <john.michael.hall gmail.com> writes:
On Saturday, 9 July 2016 at 05:40:10 UTC, ag0aep6g wrote:
 ----
 template bar(T, U...)
 if (U.length > 1)
 {
     import std.meta : staticMap;
     import std.typecons : Tuple;

     alias baz(A) = Tuple!(T, A);
     alias V = staticMap!(baz, U);
     alias TupleToFoo(T : Tuple!(Types), Types ...) = Foo!Types;
     // Alternative TupleToFoo with less complex syntax:
     // alias TupleToFoo(T) = Foo!(T.Types);
     alias bar = staticMap!(TupleToFoo, V);
 }
 ----

 Or with a more lightweight, custom wrapper:

 ----
 template bar(T, U...)
 if (U.length > 1)
 {
     import std.meta : staticMap;

     template Box(stuff ...) { alias contents = stuff; }

     alias baz(A) = Box!(T, A);
     alias V = staticMap!(baz, U);
     alias BoxToFoo(alias box) = Foo!(box.contents);
     alias bar = staticMap!(BoxToFoo, V);
 }
 ----
I'll give this a try. Thanks.
Jul 09 2016
prev sibling parent reply jmh530 <john.michael.hall gmail.com> writes:
On Saturday, 9 July 2016 at 05:40:10 UTC, ag0aep6g wrote:
 On 07/09/2016 12:33 AM, jmh530 wrote:
 I'm trying to create a tuple of variadic length containing 
 structs with
 mixed types. So for instance, given

 struct Foo(T, U)
 {
      T x;
      U y;
 }

 I want to create something like
 Tuple!(Foo!(type1, type2), Foo!(type1, type3), ..., 
 Foo!(type1, typeN)) x;

 The bar function (below) is what I've tried to use to create 
 it.

 template bar(T, U...)
      if (U.length > 1)
 {

      import std.meta : staticMap;

      template baz(A)
      {
          import std.meta : AliasSeq;

          alias baz = AliasSeq!(T, A);
      }

      alias V = staticMap!(baz, U);
      alias bar = staticMap!(Foo, V);
 }

 void main()
 {
      import std.typecons : Tuple;

      Tuple!(bar!(int, float, int)) x;
 }

 My strategy was getting something like
 AliasSeq!(AliasSeq!(type1, type2), AliasSeq!(type1, type3), 
 ... )
 and then I can staticMap over that with Foo in order to create 
 the
 correct type.

 However, I can't seem to get it working.

 Any ideas?
AliasSeq expands automatically. That means, AliasSeq!(AliasSeq!(type1, type2), AliasSeq!(type1, type3)) is the same as AliasSeq!(type1, type2, type1, type3) You can see this in action with `pragma(msg, V);` which prints "(int, float, int, int)". Obviously, the next staticMap fails then, because it gets handed a list of individual types, but it should operate on pairs of types. You need to wrap your pairs in something stronger than AliasSeq. You can use a std.typecons.Tuple or a little custom template. Then you need to unwrap it before applying Foo, because Foo works on a pair of types not a Tuple or custom wrapper. Putting it together: ---- template bar(T, U...) if (U.length > 1) { import std.meta : staticMap; import std.typecons : Tuple; alias baz(A) = Tuple!(T, A); alias V = staticMap!(baz, U); alias TupleToFoo(T : Tuple!(Types), Types ...) = Foo!Types; // Alternative TupleToFoo with less complex syntax: // alias TupleToFoo(T) = Foo!(T.Types); alias bar = staticMap!(TupleToFoo, V); } ---- Or with a more lightweight, custom wrapper: ---- template bar(T, U...) if (U.length > 1) { import std.meta : staticMap; template Box(stuff ...) { alias contents = stuff; } alias baz(A) = Box!(T, A); alias V = staticMap!(baz, U); alias BoxToFoo(alias box) = Foo!(box.contents); alias bar = staticMap!(BoxToFoo, V); } ----
I was working with the lightweight wrapper and it seemed to work for simple stuff, but then I started getting a bunch of errors when I tried to integrate it in to my project. Below is the stripped down version of what I've been working with. I think the problem is that I can't get the fillAliasSeq template to work with aliases. If I change Foo to just take types and pass something like int or float, then it works fine. Note, I originally had fillAliasSeq as a nested template within bar, but this was causing errors similar to what is brought up in this thread http://forum.dlang.org/post/mailman.578.1343005779.31962.digitalmars-d-learn puremagic.com struct Foo(alias fun, R) { } template fillAliasSeq(R, f...) { import std.meta : staticMap; template Box(stuff...) { alias contents = stuff; } alias boxAR(A) = Box!(A, R); alias fillContents = staticMap!(boxAR, f); alias contents(alias box) = Foo!(box.contents); alias fillAliasSeq = staticMap!(contents, fillContents); } template bar(funs...) { auto bar(int[] x) { import std.meta : staticMap; import std.typecons : Tuple; alias resultType = fillAliasSeq!(int[], funs); Tuple!(resultType) result; return result; } } void main() { int[] x = [1, 2, 5, 9]; alias f = (a, b) => a + b; alias g = (a, b) => a * b; //auto y = bar!(f, g)(x); //this is what I want to do alias z = fillAliasSeq!(int[], f, g); //but I can't even do this }
Jul 15 2016
parent reply Michael Coulombe <kirsybuu gmail.com> writes:
On Friday, 15 July 2016 at 17:00:09 UTC, jmh530 wrote:
 I was working with the lightweight wrapper and it seemed to 
 work for simple stuff, but then I started getting a bunch of 
 errors when I tried to integrate it in to my project.

 Below is the stripped down version of what I've been working 
 with. I think the problem is that I can't get the fillAliasSeq 
 template to work with aliases. If I change Foo to just take 
 types and pass something like int or float, then it works fine.

 Note, I originally had fillAliasSeq as a nested template within 
 bar, but this was causing errors similar to what is brought up 
 in this thread
 http://forum.dlang.org/post/mailman.578.1343005779.31962.digitalmars-d-learn puremagic.com
Your issue is this line: alias boxAR(A) = Box!(A, R); This means that A must be a type, but you are trying to instantiate it with lambdas. If you switch to: alias boxAR(alias A) = Box!(A, R); But now you are back to the "local '__lambda1' as parameter to non-global template" error. Have you considered recursive solutions? template fillAliasSeq(R, f...) { import std.meta : AliasSeq; static if (f.length == 0) { alias fillAliasSeq = AliasSeq!(); } else { alias fillAliasSeq = AliasSeq!(Foo!(f[0], R), fillAliasSeq!(R, f[1..$])); } }
Jul 15 2016
parent reply jmh530 <john.michael.hall gmail.com> writes:
On Friday, 15 July 2016 at 17:41:21 UTC, Michael Coulombe wrote:
 Your issue is this line:

 alias boxAR(A) = Box!(A, R);

 This means that A must be a type, but you are trying to 
 instantiate it with lambdas. If you switch to:

 alias boxAR(alias A) = Box!(A, R);

 But now you are back to the "local '__lambda1' as parameter to 
 non-global template" error.
I had tried it a few different and ended up with errors like that.
 Have you considered recursive solutions?
Will try that next. Thanks.
Jul 15 2016
parent jmh530 <john.michael.hall gmail.com> writes:
On Friday, 15 July 2016 at 19:24:12 UTC, jmh530 wrote:
 Have you considered recursive solutions?
Will try that next. Thanks.
I think this worked for me. A few tricks were that I had to have the fillAliasSeq template as global and also I couldn't disable the default constructor for what I was filling with it. Thanks for the help.
Jul 18 2016