Tuples, CTFE, and Sliding Template Arguments

Walter Bright newshound2 at digitalmars.com
Fri Jan 12 22:35:54 UTC 2024


Given the interest in CTFE of istrings, I have been thinking about making a 
general use case out of it instead of one specific to istrings.
---------------------

Sliding Template Arguments

Consider the following template:

```
void pluto(string s)()
{
     pragma(msg, s);
}

void test()
{
     pluto!"hello"();
}
```

This compiles because `s` is a compile time argument, and `pragma(msg, s)`
expects s to be a compile time value.

```
void pluto()(string s)
{
     pragma(msg, s);
}

void test()
{
     pluto("hello");
}
```

This fails to compile because `s` is a runtime argument that is not accessible
at compile time, even if it is inlined. (Inlining doesn't help here because 
inlining is done after CTFE and semantic analysis.)

Those examples illustrate the difference between a compile time and a runtime 
argument.

For background, to generate a tuple of elements:

```
alias AliasSeq(T...) = T;
```
and a function argument list that accepts a tuple:
```
void func(Args...)(Args args)
{
}
```
But notice that `args` are runtime arguments. It turns out there is no way
to use tuples to split an argument tuple into compile time and runtime tuples:

```
void pluto(Args...)(Args args)
{
     exec!(args[0])(args[1 .. args.length]);
}
```
This is the problem that DIP1036e ran into. It's clever solution is to have the 
compiler (because it cannot be done with metaprogramming) take the first 
argument, and use it as a compile time argument to a templated dummy value. 
Then, the type of that argument is a template with the value encoded into the 
type, which can be programmatically extracted and then processed at compile time.

The awkwardness of this is it only happens with istrings, it is not a general 
purpose capability, plus the insertion of dummy arguments into the argument list 
just so their types can be extracted.

Hence, the genesis of this proposal which describes a language capability to 
create a compile time parameter from a tuple of runtime expressions.

For lack of a better term, I'll call it "Sliding Template Arguments".

Consider a template function:

```
void pluto(string s, Args...)(Args args)
{
     pragma(msg, s);
}

void exec()
{
     pluto!"hello"(1,2,3);
}
```
which works now. But this fails to compile:
```
pluto("hello",1,2,3);
```
because there is no argument for `s`.

So, instead of issuing a compilation error, the compiler can "slide" the 
arguments to the left, so the first argument is moved into the compile time 
parameter list. Then, the call will compile.

The rule would be something like:

1. the function is a template taking a variadic runtime argument list
2. the compile time parameters are a sequence of N value parameters, followed by
the variadic type parameter.
3. the value parameters do not have default values
4. no compile time arguments are provided in the template invocation
5. the leftmost N runtime arguments are matched against the compile time parameters,
and removed from the runtime argument list
6. if they match, then the template instantiation is rewritten to reflect this
7. compilation then proceeds normally

Template Sliding thus becomes a general use facility. One interesting 
consequence of this is it opens up a whole new class of functions that can now 
do CTFE computations on the leftmost arguments.


More information about the Digitalmars-d mailing list