On Saturday, 27 October 2012 at 10:07:20 UTC, Jonathan M Davis wrote:
On Saturday, October 27, 2012 11:58:57 simendsjo wrote:
The thing is that I often doesn't really care about the type,
only that it exposes certain properties.

Then create a template constraint (or eponymous template to use in a template constraint) which tests for those properties. That's exactly what templates like isForwardRange and hasLength do for range-based operations. You just need
the same sort of thing for the set operations that you require.

So something like this then?
Should the traits module be extended with templates to query for certain behavior?

template hasDivision(T) {
enum hasDivision = isNumeric!T || __traits(compiles, {T.init/1;});
}

template castsTo(T, C) {
    enum castsTo = __traits(compiles, {cast(C)T.init;});
}

template castsToIntegral(T) {
    enum castsToIntegral =
           castsTo!(T, byte)  || castsTo!(T, ubyte)
        || castsTo!(T, short) || castsTo!(T, ushort)
        || castsTo!(T, int)   || castsTo!(T, uint)
        || castsTo!(T, long)  || castsTo!(T, ulong);
}

template hasIntegerDivision(T) {
    enum hasIntegerDivision = isIntegral!T
        || (hasDivision!T && castsToIntegral!(typeof(T.init/2)));
}
unittest {
    assert( hasIntegerDivision!int);
    assert(!hasIntegerDivision!float);

    struct Int {
        int i;
Int opBinary(string op, T)(T value) if(isIntegral!T && op == "/") {
            return Int(i/value);
        }

        T opCast(T)() if(isIntegral!T) {
            return cast(T)i;
        }
    }

    assert( hasIntegerDivision!Int);
}


Reply via email to