Not sure if this is a bug or intended behavior: import std.traits; struct S { int i; T opCast(T)() if(isFloatingPoint!T) { return cast(T)i; } }
template myIsFloatingPoint(T) { enum myIsFloatingPoint = isFloatingPoint!T || __traits(compiles, { cast(real)T.init; }); } void main() { auto s = S(10); assert(cast(real)s == 10.0); // static assert( isFloatingPoint!S); // false static assert( myIsFloatingPoint!S); static assert( myIsFloatingPoint!float); static assert(!myIsFloatingPoint!int); } Think of a Fraction or RangedInt struct for instance: import std.traits; struct Ranged(T, T minValue, T maxValue) if(isNumeric!T) { enum T max = maxValue; enum T min = minValue; T value = min; invariant() { assert(value >= min && value <= max); } T opCast()() { return value; } void opAssign(T value) { this.value = value; } bool opEquals(T value) { return this.value == value; } } void f(int v) {} void g(T)(T v) if(isNumeric!T) { } void main() { Ranged!(int, 10, 20) v; assert(v == 10); v = 20; //v = 21; // assert as expected // f(v); // ok if we would use an alias this, but then the Ranged isn't in effect anymore //g(v); // oops.. Ranged is not numeric } So.. What do I need to implement for a struct to be a valid built-in type? All valid properties (min, max etc) and operators for that type?