https://dlang.org/spec/template.html#TemplateAliasParameter
[Copied from spec]
Alias parameters enable templates to be parameterized with almost any kind of D symbol, including user-defined type names, global names, local names, module names, template names, and template instance names. Literals can also be used as arguments to alias parameters.
I've found that you can also pass function calls, i.e.
----------------------------
template Foo(alias x)
{
enum Foo = x;
}
size_t return42() { return 42; }
void main()
{
auto foo2 = Foo!(return42());
pragma(msg, typeof(foo2).stringof);
}
----------------------------
The spec should be updated to describe the true capabilities of alias template parameters. It sounds like along with symbols and literals, alias parameters can also accept compile-time values.
Comment #1 by johnnymarler — 2018-03-05T15:51:08Z
Quick clarification.
Based on the example in the comment above, the following:
Foo!return42
treats the `return42` part as a function call with no arguments instead of passing the `return42` symbol to the Foo template. Note that this is still true even if return42 takes arguments, it will treat it as an erroneous function call.
Comment #2 by ag0aep6g — 2018-03-05T16:02:31Z
(In reply to Jonathan Marler from comment #1)
> Based on the example in the comment above, the following:
>
> Foo!return42
>
> treats the `return42` part as a function call with no arguments instead of
> passing the `return42` symbol to the Foo template. Note that this is still
> true even if return42 takes arguments, it will treat it as an erroneous
> function call.
No. At that point it's an alias of the function. It gets called inside `Foo`:
----
template Foo(alias x)
{
enum Foo = x; /* This calls x. */
}
----
Comment #3 by johnnymarler — 2018-03-05T16:17:58Z
> No. At that point it's an alias of the function. It gets called inside `Foo`:
Ah I see you're right. If I add pragma(msg, typeof(x)) inside the template, it shows that x is a function (not just a uint). If I change it to:
Foo!(return42())
Then x will actually be a uint.
Going a bit further, it looks like alias parameters do accept function calls, but in that case the function call is evaluated outside the template, as demonstrated by this example:
template Foo(alias x)
{
pragma(msg, typeof(x));
enum Foo = x;
}
int return42a() { return 42; }
int return42b() { return 42; }
void main()
{
auto foo1 = Foo!(return42a());
auto foo2 = Foo!(return42b());
auto foo3 = Foo!(42);
}
If you compile this, the template Foo only gets instantiated once meaning that all 3 of these templates are the same.
Another interesting use case, it looks like you can also use expressions, i.e.
auto foo4 = Foo!(40 + 2);
Comment #4 by johnnymarler — 2018-03-05T16:26:32Z
Maybe a better description...
template "alias" parameters can accept "symbols" and "values". If a symbol is passed to the template, i.e.
MyTemplate!someSymbol
Then the symbol is passed directly to the template without being treated as an expression to evaluate. Even if the symbol is a function, the function is not called and then passed to the template, the function symbol is passed to it.
However, if an "non-symbol" expression is passed to the template, then the expression is evaluated at "compile time" and the return value passed to it, i.e.
MyTemplate!42
MyTemplate!(40 + 2)
enum x = 40;
MyTemplate!(x + 2)
auto return42() { return 42; }
MyTemplate!(return42())
All these represent the same template instantiation.
Comment #5 by github-bugzilla — 2018-06-17T05:54:01Z