CTFE calling a template: Error: expression ... is not a valid template value argument

Jens Mueller jens.k.mueller at gmx.de
Fri Sep 21 01:44:11 PDT 2012


Jonathan M Davis wrote:
> On Friday, September 21, 2012 00:11:51 Jens Mueller wrote:
> > I thought foo is interpreted at compile time.
> > There seems to be a subtle difference I'm not getting.
> > Because you can do the factorial using CTFE even though you have
> > recursion. I.e. there you have a call to the function itself. I.e. it
> > can be compiled because you just insert a call to the function. But for
> > a template you cannot issue something like call for instantiation.
> > Have to think more about it. But your answer helps a lot. Pushes me in
> > the right direction.
> 
> Okay. Straight up recursion works. So, with this code
> 
> int func(int value)
> {
>  if(value < 10)
>  return func(value + 1);
>  return value;
> }
> 
> enum var = func(5);
> 
> var would be 10. The problem is that you're trying to pass the result of a 
> recursive call as a template argument. As far as a function's behavior goes, 
> it's identical regardless of whether it's run at compile time or runtime (save 
> that __ctfe is true at compile time but not runtime). To quote the docs:
> 
> ------
> Any func­tions that ex­e­cute at com­pile time must also be ex­e­cutable at 
> run time. The com­pile time eval­u­a­tion of a func­tion does the equiv­a­lent 
> of run­ning the func­tion at run time. This means that the se­man­tics of a 
> func­tion can­not de­pend on com­pile time val­ues of the func­tion. For ex­
> am­ple:
> 
> int foo(char[] s) {
>  return mixin(s);
> }
> 
> const int x = foo("1");
> 
> is il­le­gal, be­cause the run­time code for foo() can­not be gen­er­ated. A 
> func­tion tem­plate would be the ap­pro­pri­ate method to im­ple­ment this 
> sort of thing.
> ------

Is it also illegal to do

int foo(char[] s) {
  if (__ctfe)
    return mixin(s);
  else
    return ""; // or assert(false)
}

?

Because this is executable at run time.

> You're doing something very similar to passing a function argument to a mixin 
> statement, but in this case, it's passing the result of calling a function 
> which doesn't exist yet (since it hasn't been fully compiled) to a template.
> 
> In order for your foo function to be called, it must be fully compiled first 
> (including its entire body, since CTFE needs the full definition of the 
> function, not just its signature). The body cannot be fully compiled until the 
> template that it's using is instantiated. But that template can't be compiled 
> until foo has been compiled, because you're passing a call to foo to it as a 
> template argument. So, you have a circular dependency.

I see. That's is clear to me now. Thanks.

> Normal recursion avoids this, because it only depends on the function's 
> signature, but what you're doing requires that the function be _run_ as part 
> of the process of defining it. That's an unbreakable circular dependency and 
> will never work. You need to redesign your code so that you don't require a 
> function to call itself while it's being defined. Being called at compile time 
> is fine, but being called while it's being compiled is not.

But if the function wasn't compiled but interpreted at compile time it
would be possible, wouldn't it?

Jens


More information about the Digitalmars-d mailing list