Macro templates [Was: Re: Compile-time fold expression vs recursive template]
Paul Backus
snarwin at gmail.com
Fri Jun 19 18:30:28 UTC 2020
On Friday, 19 June 2020 at 17:36:54 UTC, Stefan Koch wrote:
>
> We should talk and band together.
> Multiple competing proposals won't help here.
>
> We at least have gained some clarity about the problem.
> Now let's gain some clarity about the solution space.
Here's my idea: we introduce a new kind of template called "macro
templates" (working title).
Macro templates are like regular templates, but with two
differences. First, they are subject to the following
restrictions:
- A macro template may only contain `enum` and `alias`
declarations.
- A macro template must have an eponymous member.
Second, each instantiation of a macro template is evaluated
independently, and once evaluated is immediately replaced in the
source code with the value of its eponymous member. All
intermediate results are discarded.
To give a concrete example, here's how `staticMap` could be
written as a macro template:
macro template staticMap(alias F, Args...)
{
static if (Args.length == 0)
alias staticMap = AliasSeq!();
else
alias staticMap = AliasSeq!(F!(Args[0]), staticMap!(F,
Args[1 .. $]));
}
And here's how an instantiation of that version of `staticMap`
would be evaluated:
alias result = staticMap!(ConstOf, int, char, double);
... = AliasSeq!(
ConstOf!int,
staticMap!(ConstOf, char, double));
... = AliasSeq!(
ConstOf!int,
AliasSeq!(
ConstOf!char,
staticMap!(ConstOf, double)));
... = AliasSeq!(
ConstOf!int,
AliasSeq!(
ConstOf!char,
AliasSeq!(
ConstOf!double,
staticMap!(ConstOf))));
... = AliasSeq!(
ConstOf!int,
AliasSeq!(
ConstOf!char,
AliasSeq!(
ConstOf!double,
AliasSeq!())));
The total cost here, in terms of symbol-table bloat, is:
- 4 instances of `AliasSeq`
- 3 instances of `ConstOf`
Notice that `staticMap` itself has completely disappeared. By
making `AliasSeq` and `ConstOf` into macro templates as well, we
can get the entire thing to reduce down to:
alias result = (const(int), const(char), const(double));
That is, we can eliminate *all* symbol-table bloat, and retain
only the final result.
To achieve Nick Treleaven's goal of re-using the same Scope for
each "iteration", all that is necessary is for the compiler to
implement tail-call optimization for macro templates (a
well-known and well-studied technique). `staticMap` can then be
easily re-written to use a tail-recursive helper template.
One big advantage of this approach is that it is largely
backwards compatible. Many existing templates can be converted
simply by adding the `macro` keyword to their definition, without
breaking existing code that depends on them.
More information about the Digitalmars-d
mailing list