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