static assert not printing out along the error diagnostic

jfondren julian.fondren at gmail.com
Wed Jul 14 06:28:37 UTC 2021


On Wednesday, 14 July 2021 at 03:06:06 UTC, someone wrote:
> in main() ... so then I went to the D docs and to Ali's book 
> afterward and there I tested his example to same results.

The current behavior seems like it could be taken for a bug, or 
at least room for improvement in letting static assertions fail 
faster than other template instantiation, but the workaround 
seems to be to require all branches of a static if to be valid 
from the perspective of the rest of the code. Which is very easy 
to do if you just don't have these branches at all.

case 1:

```d
public struct gudtUGC(typeStringUTF) {
    static if (! (is (typeStringUTF == string) || is 
(typeStringUTF == wstring) || is (typeStringUTF == dstring))) {
       static assert(false, r"ooops … gudtUGC structure requires 
[string|wstring|dstring] ≠ ["d ~ typeStringUTF.stringof ~ r"]"d);
    } else {
       // actual structure code
    }
}
```

alternate 1:
- pull tests out into a named enum template, like std.traits
- always static assert enum, rather than conditionally asserting 
false
- always have the rest of the code

```d
enum isString(T) = is(T == string) || is(T == wstring) || is(T == 
dstring);
// very similar to std.traits.isSomeString

struct gudtUGC(T) {
     static assert(isString!T, "error message");
     // unconditional structure code
}
```

case 2:

```d
struct MyType(T) {
     static if (is (T == float)) {
         alias ResultType = double;

     } else static if (is (T == double)) {
         alias ResultType = real;

     } else {
         static assert(false, T.stringof ~ " is not supported");
     }
     // code relying on some ResultType
}
```

alternate 2a:
- create a type function with std.meta

```d
enum SmallFloat(T) = is(T == float) || is(T == double);

template largerFloat(T) {
     import std.meta : AliasSeq, staticIndexOf;

     static assert(SmallFloat!T, T.stringof ~ " is not supported");

     alias largerFloat = AliasSeq!(void, double, 
real)[1+staticIndexOf!(T, AliasSeq!(float, double))];
}

struct MyType(T) {
     alias ResultType = largerFloat!T;
     // code relying on some ResultType
}
```

alternate 2b:
- at least make all the branches valid

```d
enum SmallFloat(T) = is(T == float) || is(T == double);

struct MyType(T) {
     static assert(SmallFloat!T, T.stringof ~ " is not supported");
     static if (is(T == float)) {
         alias ResultType = double;
     } else static if (is(T == double)) {
         alias ResultType = real;
     } else {
         alias ResultType = void; // dummy
     }
     // code relying on ResultType
}
```

A benefit of having tests like SmallFloat is that you can use 
them with template constraints...

```d
void moreWork(T)() if (SmallFloat!T) { }

unittest {
     moreWork!float; // this is fine
     moreWork!real; // !
}
```

... and get readable error messages out of the box, without 
having to write static assert messages:

```
example.d(23): Error: template instance `example.moreWork!real` 
does not match template declaration `moreWork(T)()`
   with `T = real`
   must satisfy the following constraint:
`       SmallFloat!T`
```


More information about the Digitalmars-d-learn mailing list