Thread overview
Concatenating compile time sequences
Mar 02, 2019
Victor Porton
Mar 02, 2019
H. S. Teoh
Mar 03, 2019
aliak
March 02, 2019
I try to split a compile time sequence of types and names into a sequence consisting of two-element subsequences (each of type and name).

That is, I want to transform:

(int, "x", float, "y", double, "z")

into

(AliasSeq!(int, "x"), AliasSeq!(float, "y"), AliasSeq!(double, "z"))

I am trying like this:

private alias enum processFields() = AliasSeq!();

private alias enum processFields(T, name, Fields...) =
    AliasSeq!(AliasSeq!(T, name), processFields!(Fields));

But the above would (as I understand) make AliasSeq! returned by the recursively called processFields an element of the parent sequence rather than its tail subsequence as it should.

Please help to fix the above code. I want namely a recursive implementation like the above, because I am going to generalize it for some more complex cases.
March 01, 2019
On Sat, Mar 02, 2019 at 02:16:22AM +0000, Victor Porton via Digitalmars-d-learn wrote:
> I try to split a compile time sequence of types and names into a sequence consisting of two-element subsequences (each of type and name).
> 
> That is, I want to transform:
> 
> (int, "x", float, "y", double, "z")
> 
> into
> 
> (AliasSeq!(int, "x"), AliasSeq!(float, "y"), AliasSeq!(double, "z"))

Keep in mind that sequences produced by AliasSeq are auto-expanding, meaning the above construct will automatically flatten into a flat AliasSeq!(int, "x", float, "y", double, "z").  If that's not what you want, you need to wrap your subsequences in a separate, non-eponymous template.


> I am trying like this:
> 
> private alias enum processFields() = AliasSeq!();

I'm not sure what "alias enum" is supposed to mean; is that a typo? Surely you mean just "alias"?


> private alias enum processFields(T, name, Fields...) =
>     AliasSeq!(AliasSeq!(T, name), processFields!(Fields));

This line doesn't do what you think it does, because of auto-expansion. It's essentially exactly the same thing as:

	private alias processFields(T, name, Fields...) =
		AliasSeq!(T, name, processFields!(Fields));

i.e., the nested AliasSeq has no effect.


> But the above would (as I understand) make AliasSeq! returned by the recursively called processFields an element of the parent sequence rather than its tail subsequence as it should.

If you want anything that retains a nested structure, you cannot use AliasSeq because of auto-expansion.  You need to define your own, non-eponymous template container, e.g.:

	template MySeq(T...) {
		alias data = T;
	}

	alias processFields(T, name, Fields...) =
		AliasSeq!(MySeq!(T, name), MySeq!(processFields!(Fields)));

The MySeq!(...) "protect" their contents from flattening into the outer list, while the outer AliasSeq causes individual MySeq!(...)'s to be promoted to the top level sequence rather than producing a tree-like structure.

Note that to access the data inside a MySeq, you'll have to use .data, for example:

	alias fields = processFields!(int, "x", float, "y");

	alias type0 = fields[0].data[0]; // int
	string name0 = fields[0].data[1]; // "x"
	alias type1 = fields[1].data[0]; // float
	string name1 = fields[1].data[1]; // "y"

Hope this helps.


T

-- 
Windows: the ultimate triumph of marketing over technology. -- Adrian von Bidder
March 03, 2019
On Saturday, 2 March 2019 at 02:38:09 UTC, H. S. Teoh wrote:
> On Sat, Mar 02, 2019 at 02:16:22AM +0000, Victor Porton via Digitalmars-d-learn wrote:
>> [...]
>
> Keep in mind that sequences produced by AliasSeq are auto-expanding, meaning the above construct will automatically flatten into a flat AliasSeq!(int, "x", float, "y", double, "z").  If that's not what you want, you need to wrap your subsequences in a separate, non-eponymous template.
>
>
>> [...]
>
> I'm not sure what "alias enum" is supposed to mean; is that a typo? Surely you mean just "alias"?
>
>
>>     [...]
>
> This line doesn't do what you think it does, because of auto-expansion. It's essentially exactly the same thing as:
>
> 	private alias processFields(T, name, Fields...) =
> 		AliasSeq!(T, name, processFields!(Fields));
>
> i.e., the nested AliasSeq has no effect.
>
>
>> [...]
>
> If you want anything that retains a nested structure, you cannot use AliasSeq because of auto-expansion.  You need to define your own, non-eponymous template container, e.g.:
>
> 	template MySeq(T...) {
> 		alias data = T;
> 	}
>
> 	alias processFields(T, name, Fields...) =
> 		AliasSeq!(MySeq!(T, name), MySeq!(processFields!(Fields)));
>
> The MySeq!(...) "protect" their contents from flattening into the outer list, while the outer AliasSeq causes individual MySeq!(...)'s to be promoted to the top level sequence rather than producing a tree-like structure.
>
> Note that to access the data inside a MySeq, you'll have to use .data, for example:
>
> 	alias fields = processFields!(int, "x", float, "y");
>
> 	alias type0 = fields[0].data[0]; // int
> 	string name0 = fields[0].data[1]; // "x"
> 	alias type1 = fields[1].data[0]; // float
> 	string name1 = fields[1].data[1]; // "y"
>
> Hope this helps.
>
>
> T

There's a package called bolts that has an AliasPack defined that could allow you to do something like:

template split(seq...) if (seq.length % 2 == 0) {
    static if (seq.length >= 2) {
    	alias Pair = AliasPack!(seq[0], seq[1]);
    	alias split = AliasSeq!(Pair, .split!(seq[2..$]));	
    } else {
        alias split = AliasSeq!();
    }
}

Running code: https://run.dlang.io/is/lfTOBz

Cheers,
- Ali