Template Lambdas
Quirin Schroll
qs.il.paperinik at gmail.com
Sat Sep 28 02:05:36 UTC 2024
It’s still work-in-progress, but this is [the current
state](https://github.com/Bolpat/dmd/tree/LambdaTemplates): An
elaborate lambda (one starting with `function` or `delegate`) can
optionally carry a template parameter list and in that case,
optionally a constraint. How embarrassing is it that C++ has
explicit template parameters for lambdas for 4 years now and D
doesn’t have them?
The syntax:
```d
function template(TemplateParameters) ReturnType? Parameters?
Attributes? Constraint? Contracts? Body
```
When you use `template`, the parameter list is a regular function
parameter list, i.e. there is no `(x)` with automatic type. This
is because it can’t be done in general. But what it gives you is
variadic lambdas!
```d
template tt(alias f)
{
enum tt = f(1, "abc", true, 3.14);
}
enum x = tt!(function template(Ts...)(Ts args) {
import std.conv : to;
string result;
static foreach (alias arg; args)
{
result ~= arg.to!string;
}
return result;
});
pragma(msg, x); // 1abctrue3.14
```
For example, this is what I want to be able to do:
```d
import std.traits : isIntegral;
static assert(allSatisfy!(
function template(T) => isIntegral!T && T.max > 20_000,
short,
int
));
static assert(!allSatisfy!(
function template(T) => isIntegral!T && T.max > 20_000,
byte,
short,
int
));
```
Unfortunately, this doesn’t work. `T` is not in scope in the
body. For whatever reason.
However, it *is* in scope for the parameter list. So I can do:
```d
import std.traits : isIntegral;
static assert(allSatisfy!(
function template(X)(bool result = isIntegral!X && X.max >
20_000) => result,
short,
int
));
static assert(!allSatisfy!(
function template(X)(bool result = isIntegral!X && X.max >
20_000) => result,
byte,
short,
int
));
```
Now, I have to admit, `allSatisfy` isn’t `std.meta.allSatisfy`
because that one works with `enum bool` templates only, not with
functions that require being called.
But the above is not wishful thinking. I implemented my own
`allSatisfy` that should work with `enum bool` templates, but
also function pointers and delegates that can be called with no
arguments and return `bool`.
```d
template allSatisfy(alias cond, Ts...)
{
static foreach (T; Ts)
{
static if (!is(typeof(allSatisfy) == bool)) // not yet
defined
{
static if (cast(bool)cond!T) // true when `cond` is a
FP or delegate …
{
// … and if it is …
static if (is(typeof( cond!T) == delegate)
|| is(typeof(*cond!T) == function))
{
// … and the call returns `false` …
static if (!cond!T())
{
// … `T` failed.
enum bool allSatisfy = false;
}
}
}
else
{
enum bool allSatisfy = false;
}
}
}
static if (!is(typeof(allSatisfy) == bool)) // if not yet
defined
{
enum allSatisfy = true;
}
}
```
For reasons beyond my understanding, the `cast(bool)` is needed
before `const!T`.
More information about the Digitalmars-d
mailing list