www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Template Lambdas

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`.
Sep 27