On Thursday, 18 July 2013 at 05:57:48 UTC, H. S. Teoh wrote:
On Thu, Jul 18, 2013 at 07:23:57AM +0200, JS wrote:
[...]
Thanks, this has made it much clearer.
Something like
foreach(a; StrSplit!(s))
foreach(b; StrSplit !(a))
does work because the second StrSplit uses a "ctfe-time
variable"
instead of a "template-time variable".
My logic was:
1. first StrSplit resolved
2. first foreach evaluated
3. second StrSplit resolved
4. second foreach evaluated
while it actually is
1. first StrSplit resolved
2. second StrSplit resolved
3. foreach's resolved
because template expansion happens before any ctfe expansion.
I guess I was thinking the compiler would be smart enough to
interleave template expansion and ctfe code(which would be
much more
powerfull).
Effectively template expansion is a sort of pre-processing to
ctfe
code and must be static as far as ctfe's go.
[...]
That's one way to think of it, yes.
As for interleaving template expansion vs. ctfe evaluation, the
compiler
*does* do that to some extent. For example, this code does
work:
// Function that can be evaluated by CTFE
int func(int x) pure {
int sum;
foreach (i; 0..x) {
sum += i;
}
return sum;
}
// Force CTFE evaluation
enum myConst = func(10);
// Template that requires an int parameter.
template MyTemplate(int x) {
enum MyTemplate = x+10;
}
// Instantiate template with enum produced by CTFE.
pragma(msg, MyTemplate!myConst);
void main() {}
The reason this works is because the compiler is smart enough
to figure
out that myConst requires func, so it first compiles func far
enough to
be CTFE-evaluable, then it evaluates func to produce the value
of
myConst, and then myConst is used to instantiate MyTemplate.
You could
think of it as the compiler compiling different parts of the
program at
different rates, so func has been compiled into a runnable
state, but
the pragma(msg) line is still at the template expansion state.
Note, however, that the template-before-CTFE limitation still
applies:
func can't require template expansion while it's running; it
must be
entirely compilable into runnable state before CTFE can
evaluate it.
Other parts of the program can still remain at the
template-expansion
stage, so they can take some CTFE-produced values as template
parameters. But you can't make any reverse dependencies /
loops. You're
OK if you already have runnable code that can then produce
template
parameters for other code, but you can't run CTFE and template
expansion
simultaneously in the *same* code.
So the compiler is actually pretty smart about reordering these
things,
but the fundamental limitation of template-before-CTFE still
applies to
each individual code unit. After all, you can't run code that
hasn't
been fully expanded by the template system yet.
T
Thanks. Your reply was extremely helpful and I think I'll have
less pms over ctfe's.