Thread overview
Relax template sequence parameters, explicit template sequence arguments
Feb 20
monkyyy
February 20

Template sequence parameters (Ts...) must be the last parameter of a template. That also means one can only have one of them per template.

To facilitate passing a sequence to a sequence parameter, a new syntactical construct is needed. For simplicity, I’ll use !(). It would only be needed if a template with a non-terminal sequence parameter is explicitly instantiated.

void f(Ts..., Rs...)(Ts ts, Rs rs) { }
f(); // Ts = !(), Rs = !()
f(1,2,3); // Ts = !(int, int, int), Rs = !()
f!(!(int))(1,2,3); // Ts = !(int), Rs = !(int, int)
f!(!(int), !(int, long))(1,2,3); // Ts = !(int), Rs = !(int, long)
f!(!int, int, long)(1,2,3); // Ts = !(int), Rs = !(int, long)
// The `()` are optional if it’s a single token
// The last sequence matches individually stated arguments (current behavior)

Other use case: Make it hard to pass certain arguments

void f(Ts..., size_t line = __LINE__)(Ts args) { pragma(msg, line); }
f!(int, int)(1, 2); // good, Ts = !(int, int)
f!(int, int, 0)(1, 2); // error, tries Ts = !(int, int, 0), but `0` is not a type
f!(!(int, int), 0)(1, 2); // good (won’t happen by accident)

Note: !(Args…) would not produce an AliasSeq!(Args…). It’d be part of the template argument list syntax:

 TemplateInstance:
    Identifier TemplateArguments

 TemplateArguments:
    ! ( )
    ! ( TemplateArgumentList )
    ! TemplateSingleArgument

 TemplateArgumentList:
    TemplateArgument
    TemplateArgument ,
    TemplateArgument , TemplateArgumentList

 TemplateArgument:
    Type
    AssignExpression
    Symbol
+   TemplateArguments
February 19
On Wednesday, February 19, 2025 8:46:08 PM MST Quirin Schroll via dip.ideas wrote:
> Template sequence parameters (`Ts...`) must be the last parameter of a template. That also means one can only have one of them per template.
>
> To facilitate passing a sequence to a sequence parameter, a new syntactical construct is needed. For simplicity, I’ll use `!()`. It would only be needed if a template with a non-terminal sequence parameter is explicitly instantiated.
>
> ```d
> void f(Ts..., Rs...)(Ts ts, Rs rs) { }
> ```
> ```d
> f(); // Ts = !(), Rs = !()
> f(1,2,3); // Ts = !(int, int, int), Rs = !()
> f!(!(int))(1,2,3); // Ts = !(int), Rs = !(int, int)
> f!(!(int), !(int, long))(1,2,3); // Ts = !(int), Rs = !(int, long)
> f!(!int, int, long)(1,2,3); // Ts = !(int), Rs = !(int, long)
> // The `()` are optional if it’s a single token
> // The last sequence matches individually stated arguments
> (current behavior)
> ```
>
> Other use case: Make it hard to pass certain arguments
> ```d
> void f(Ts..., size_t line = __LINE__)(Ts args) { pragma(msg,
> line); }
> ```
> ```d
> f!(int, int)(1, 2); // good, Ts = !(int, int)
> f!(int, int, 0)(1, 2); // error, tries Ts = !(int, int, 0), but
> `0` is not a type
> f!(!(int, int), 0)(1, 2); // good (won’t happen by accident)
> ```
>
> Note: `!(Args…)` would not produce an `AliasSeq!(Args…)`. It’d be
> part of the template argument list syntax:
> ```diff
>   TemplateInstance:
>      Identifier TemplateArguments
>
>   TemplateArguments:
>      ! ( )
>      ! ( TemplateArgumentList )
>      ! TemplateSingleArgument
>
>   TemplateArgumentList:
>      TemplateArgument
>      TemplateArgument ,
>      TemplateArgument , TemplateArgumentList
>
>   TemplateArgument:
>      Type
>      AssignExpression
>      Symbol
> +   TemplateArguments
> ```

Because !() is already used for instantiating templates, I don't see how this could be anything other than confusing.

And while it would occasionally be useful to have multiple variadic lists of template parameters or arguments, it really doesn't come up very often. So, I question that complicating the language further to support them is worth it. As it is, you can always just wrap them in another template if you really need them.

What are trying to do where something like this would really be needed?

- Jonathan M Davis




February 20

On Thursday, 20 February 2025 at 03:46:08 UTC, Quirin Schroll wrote:

>

Template sequence parameters (Ts...) must be the last parameter of a template. That also means one can only have one of them per template.

template foo(T...){
template foo(S...){
void foo(U...)(){
    T.stringof.writeln;
    S.stringof.writeln;
    U.stringof.writeln;
}}}

unittest{
    alias a=foo!(int,float);
    alias b=a!bool;
    b!(1);
}

If the "multi template argument" thing was removed it would just work


>

Other use case: Make it hard to pass certain arguments

>

void f(Ts..., size_t line = LINE)(Ts args) { pragma(msg, line); }

Should just remove the restriction that ... must come last

void foo(T...,A...,R)(R r,A args,int line=__LINE__){...}

buzz.foo!(bar,fizz)(1,2,3);// r=buzz,T=bar,fizz,args=1,2,3