Template constraints should introduce identifiers inside their scopes
Paul Backus
snarwin at gmail.com
Wed Sep 21 12:32:38 UTC 2022
On Wednesday, 21 September 2022 at 12:18:19 UTC, Quirin Schroll
wrote:
> On Wednesday, 21 September 2022 at 11:23:57 UTC, HuskyNator
> wrote:
>> Consider these semantically identical functions:
>>
>> ```d
>> void foo(M)(M list) {
>> static if (is(M : T[L], T, uint L)) {
>> pragma(msg, "Length: " ~ L.to!string); // Length: 2
>> }
>> }
>>
>> void bar(M)(M list) if (is(M : T[L], T, uint L)) {
>> pragma(msg, "Length: " ~ L.to!string); // undefined
>> identifier 'L'
>> }
>> ```
>> [...]
>>
>> Although semantically the same,
>
> They are not semantically the same. The first can be
> instantiated with any type and conditionally makes an output
> (it is empty otherwise), the other says it cannot be
> instantiated unless the arguments have specific properties.
If you want the semantics to match exactly you can replace the
`static if` with a `static assert` (or add `else static
assert(0);`).
> Your suggestion is very much independent of the DbI vs
> constraints. You want identifiers defined in a constraint to be
> visible in the body of the template. This is possible in simple
> cases like yours, but what if the `is` check is nested or
> negated?
`static if` already handles these cases. I don't know exactly
what the rules are (needs better documentation), but presumably
they would work the same way for constraints.
> In your case,
> ```d
> void foo(M : T[L], T, uint L)(M list) { }
> ```
> does the trick.
As I'm sure you're aware, there are cases where the desired
constraint cannot be expressed using template specializations.
For example:
```d
auto fun(R)(R r)
if (isInputRange!R && is(ElementType!R == T[], T))
```
More information about the Digitalmars-d
mailing list