digitalmars.D - Template Lambdas
- Quirin Schroll (111/111) Sep 27 It’s still work-in-progress, but this is [the current
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