[Issue 24629] New: Allow more than 1 set of template parameters

d-bugmail at puremagic.com d-bugmail at puremagic.com
Tue Jun 25 16:10:16 UTC 2024


https://issues.dlang.org/show_bug.cgi?id=24629

          Issue ID: 24629
           Summary: Allow more than 1 set of template parameters
           Product: D
           Version: D2
          Hardware: All
                OS: All
            Status: NEW
          Severity: enhancement
          Priority: P1
         Component: dmd
          Assignee: nobody at puremagic.com
          Reporter: qs.il.paperinik at gmail.com

Apart from a `template` template, templates can be defined by giving the
construct template parameters, e.g. `class C(T)`, `void f(T)(T x)`, `enum
isConst(T) = …`, `alias Unshared(T) = …`, etc.

Those are equivalent to a `template` template with the respective construct
with the same name inside of it.

Why only allow one level of nesting? There is no good reason not to allow for
multiple nesting levels:
```d
void f(T)(U)(T t, U u) { … }
```
would be lowered to:
```d
template f(T)
{
    template f(U)
    {
        void f(T t, U u) { … }
    }
}
```

UFCS and IFTI work in a specific way with nested templates: Template arguments
can be inferred for the innermost `template`. In the example, that would mean
that callers _must_ provide `T` and the compiler can infer `U`.

Example uses cases can be merging `opAssign` and `opOpAssign`:
```d
struct S
{
    alias opAssign = opOpAssign!"";
    template opOpAssign(string op)
    {
        auto opOpAssign(R)(R rhs) { … }
    }
}
```
the latter could be:
```d
auto opOpAssign(string op)(R)(R rhs) { … }
```

Note that in D, a set of template arguments can only contain one sequence
argument. When more are needed, nested templates are necessary.

I have encountered a case where 3 sets of template arguments would be useful:
- The uppermost level is a customization point (one provides a boolean); the
module exposes two aliases, one for the `true` and one for the `false`
instance. Those are almost identical and implementing that twice makes no
sense.
- The next level is any number of lambdas
- The innermost level takes the types of the arguments (which are usually
inferred).

Using that, instead of:
```d
alias matchByType = matchByTypeImpl!false;
alias matchByTypeExact = matchByTypeImpl!true;

private template matchByTypeImpl(bool exact)
{
    template matchByTypeImpl(fs...)
    {
        auto ref matchByTypeImpl(T)(auto ref T x)
        {
            …
        }
    }
}
```
I could write:
```d
alias matchByType = matchByTypeImpl!false;
alias matchByTypeExact = matchByTypeImpl!true;
private template matchByTypeImpl(bool exact)(fs...)(T)(auto ref T x)
{
    …
}
```

--


More information about the Digitalmars-d-bugs mailing list