std.traits.ParameterIdentifierTuple producing empty results.

Carl Sturtivant sturtivant at gmail.com
Tue Apr 2 00:28:50 UTC 2024


On Monday, 1 April 2024 at 18:20:43 UTC, Nick Treleaven wrote:
> I don't think it's possible to make the `is(__parameters)` 
> check work there without changing the language. Parameter names 
> in a function type seem to be lost once that type is used to 
> instantiate a template:
>
> ```d
> void f(T)() {
>     static if (is(T PT == __parameters))
>         pragma(msg, PT);
> }
> void foo(int i, char c);
> void main()
> {
>     static if (is(typeof(foo) PT == __parameters))
>         pragma(msg, PT);
>
>     f!(typeof(foo));
> }
> ```
> Output:
> ```
> (int i, char c)
> (int, char)
> ```
> And that makes sense because otherwise a function type with 
> different parameter names would need to instantiate a separate 
> instance of the template in order to preserve the identifiers. 
> So if that happened, function types with different identifiers 
> would not always compare equal as types.

Very interesting and pertinent! Thank you. I looked into `is()` 
with `__parameters` and the documentation is a bit sparse, 
however eventually I found that I could extract the parameter 
names without CTFE provided I avoided stripping them out through 
instantiating a template with them (following your conclusion 
above). I found [this 
posting](https://forum.dlang.org/post/vpjpqfiqxkmeavtxhyla@forum.dlang.org) by one of the forum's great authors that showed the way after that.

Here is what I eventually arrived at, where `PROTO` is a function 
type with parameter names in it.
```D
static if( is(PROTO Params == __parameters) ) {
         enum paramNames = 
mixin("["~RequestParams!(Params.length)~"]");
         pragma(msg, paramNames.stringof);
```
Here the trick is to have the template `RequestParams` produce a 
string containing a comma separated series of substrings of the 
form `__traits(identifier,Params[?..?])` where the slice is 
[0..1], [1..2], ..., i.e. one for each parameter, so that when 
mixed in `Params` is asked to provide an array of parameter names 
where each parameter in turn is given by a single element slice.

Just using an index only produces the type of a parameter, but 
taking slices of any size seems to keep the parameter names. 
Similar name-discarding behavior is found when static foreach 
iterates over `Params`, implicitly indexing it.

I naively defined `RequestParams` recursively, using 
`std.format.format` to substitute indexes.
```D
template RequestParams(int N) {
     static if( N==0 )
         enum RequestParams = "";
     else
         enum RequestParams = RequestParams!(N-1)~
             format("__traits(identifier,Params[%s..%s]), ", N-1, 
N);
}
```



More information about the Digitalmars-d mailing list