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-le...@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
}