1 enum isFoo(T) = is(typeof(checkFoo!T)); 2 3 4 template isBar(T, U) 5 { 6 enum isBar = is(typeof(checkBar!(T, U))); 7 } 8 9 @models!(Foo, isFoo) //as a UDA 10 struct Foo 11 { 12 void foo() {} 13 static assert(models!(Foo, isFoo)); //as a static assert 14 } 15 16 @models!(Bar, isBar, byte) //as a UDA 17 struct Bar 18 { 19 byte bar; 20 static assert(models!(Bar, isBar, byte)); //as a static assert 21 } 22 23 // can't assert that, e.g. !models!(Bar, isFoo) - 24 // the whole point of `models` is that it doesn't compile 25 // when the template constraint is not satisfied 26 static assert(!__traits(compiles, models!(Bar, isFoo))); 27 static assert(!__traits(compiles, models!(Foo, isBar, byte)));
A static assertion that a type satisfies a given template constraint. It can be used as a UDA or in a static assert to make sure that a type conforms to the compile-time interface the user expects it to. The difference between using models and a simple static assert with the template contraint is that models will instantiate the failing code when the constraint is not satisfied, yielding compiler error messages to aid the user.
The template contraint predicate must start with the word is (e.g. isInputRange) and an associated template function with the "is" replaced by "check" should exist (e.g. checkInputRange) and be defined in the same module.