September 19, 2013
On Thu, Sep 19, 2013 at 09:12:10PM +0200, Marek Janukowicz wrote:
> Ali Çehreli wrote:
[...]
> > As far as I know, static foreach is only for tuples (or TypeTuples). If you can generate the AA as a tuple, then the foreach will be evaluated at compile time.
> 
> I read your articles about tuples and templates and it all now makes more sense (why is your book not linked on dlang.org? It is much better stuff for beginners than official D docs). However, there is still one thing I struggle with: how do I create a tuple at compile time if I'm getting information I want to put into it in a foreach? All the examples I found create a tuple with all it's attributes available, while I get mine in an iterative manner...
[...]

Hmm. That's a hard one. How do you generate your attributes? My first impression -- though I could be wrong -- is that you can't modify a type tuple dynamically, that is, once created, a tuple can't be changed, you can only make new tuples out of it. So first, you'd have to factor out your generated attributes so that they can be generated by, for example, instantiating a template with an integer index argument.

For example, say you define a template like this:

	template GenerateElement(int i) {
		// This is just an example, the point is that the
		// template returns something different depending on the
		// index i.
		static if (i==0)
			alias GenerateElement = byte;
		else static if (i==1)
			alias GenerateElement = short;
		else static if (i==2)
			alias GenerateElement = int;
		else static if (i==3)
			alias GenerateElement = float;
		else static if (i==4)
			alias GenerateElement = double;
		else static assert(0, "i is out of range");
	}

Then say you want to assemble a tuple out of a given set of indices, so
that, for example, MakeTupleFromIndices!(0,2,3) would return (byte, int,
float), and MakeTupleFromIndices!(1,4) would return (short, double). You
would then write it like this:

	template MakeTupleFromIndices(indices...) {
		alias MakeTupleFromIndices =
			TypeTuple!(GenerateElement!(indices[0]),
				MakeTupleFromIndices!(indices[1..$]));
	}

	static assert(is(MakeTupleFromIndices!(0, 2, 4) ==
			TypeTuple!(byte, int, double)));

This is a recursive template that assembles the final tuple piece-by-piece. Each piece is looked up by instantiating GenerateElement, which you can adapt to do whatever it is you need to do to determine the desired type.

Once you have the TypeTuple, you can then use it to create Tuples of the desired type:

	// Same as saying: alias Tuple1 = Tuple!(int, int, float);
	alias Tuple1 = Tuple!(MakeTupleFromIndices!(2, 2, 3));
	Tuple1 t1 = tuple(1, 2, 1.0);
	Tuple1 t2 = tuple(0, 1, 5.5);

	// Same as saying: alias Tuple2 = Tuple!(double, byte);
	alias Tuple2 = Tuple!(MakeTupleFromIndices!(4, 0));
	Tuple2 u1 = tuple(3.14159, 0xff);
	Tuple2 u2 = tuple(1.61803, 0xfe);

Of course, if you want to generate the values at compile-time as well, then you'll have to use value tuples (which are actually the same as TypeTuples -- the compiler built-in tuples can contain both types and values, so "TypeTuple" is actually a misnomer). The most obvious way is to use recursive templates in the same way as above to assemble the tuple piecemeal, for example:

	template EvenNumbers(int n) {
		static if (n==1)
			alias EvenNumbers = TypeTuple!(n*2);
		else
			// This takes advantage of auto-expansion of
			// tuples.
			alias EvenNumbers =
				TypeTuple!(EvenNumbers!(n-1), n*2);
	}

	// Prints: tuple(2, 4, 6, 8, 10)
	pragma(msg, EvenNumbers!5);

Hope this helps.


T

-- 
Those who've learned LaTeX swear by it. Those who are learning LaTeX swear at it. -- Pete Bleackley
September 19, 2013
On 09/19/2013 12:12 PM, Marek Janukowicz wrote:

> (why is your book not linked on dlang.org?

It will appear there once the translation is complete.

> how do I create a tuple at compile time if I'm getting
> information I want to put into it in a foreach? All the
> examples I found create a tuple with all it's attributes
> available, while I get mine in an iterative manner...

I think the automatic expansion of a TypeTuple as parameter list may be used in a some sort of recursive templates:

import std.typetuple;

void main()
{
    alias t0 = TypeTuple!(1, "hello");
    alias t1 = TypeTuple!(t0, 2.3);    // Adds to t0

    pragma(msg, t1);    // prints tuple(1, "hello", 2.3)
}

Ali

September 20, 2013
On 09/19/2013 12:53 PM, H. S. Teoh wrote:

> I hope you're
> thoroughly confused and utterly perplexed by now

No, because you explained it very well. :)

> readers should instead be directed to std.traits

Indeed, I will add some :) of this information to the Traits chapter which comes later in the book.

Ali

September 20, 2013
On 09/19/2013 04:32 AM, Dicebot wrote:

> Some obvious catches:

Thank you. I have made those changes except the following one.

> Variadic template arg chapter should probably mention "variadic args of
> length 1" idiom used to have parameter accepting types, values and
> aliases at once.

Could you please expand on that.

Thank you,
Ali

September 20, 2013
On Friday, 20 September 2013 at 06:20:09 UTC, Ali Çehreli wrote:
> On 09/19/2013 04:32 AM, Dicebot wrote:
>
> > Some obvious catches:
>
> Thank you. I have made those changes except the following one.
>
> > Variadic template arg chapter should probably mention
> "variadic args of
> > length 1" idiom used to have parameter accepting types,
> values and
> > aliases at once.
>
> Could you please expand on that.
>
> Thank you,
> Ali

Quoting Phobos:

```
template fullyQualifiedName(T...)
    if (T.length == 1)
{
    static if (is(T[0]))
        enum fullyQualifiedName = fullyQualifiedNameImplForTypes!(T[0], false, false, false, false);
    else
        enum fullyQualifiedName = fullyQualifiedNameImplForSymbols!(T[0]);
}
```

It is a relatively common idiom because there is no other way to express a single template parameter that accepts anything.
1 2
Next ›   Last »