On Sat, 28 Jul 2012 22:47:01 +0200, Chad J <chadjoan@__spam.is.bad__gmail.com> wrote:

isInputRange!___ r2 = [1,2,3].some.complex.expression();

It doesn't make sense. isInputRange!() isn't a type, so how do I constrain what type is returned from some arbitrary expression?

So far the only way I know how to do this is to pass it through a template and use template constraints:

auto makeSureItsARange(T)(T arg) if ( isInputRange!T )
{
        return arg;
}

auto r2 = makeSureItsARange([1,2,3].some.complex.expression());

however, the above is unreasonably verbose and subject to naming whimsy.


import std.typetuple : allSatisfy;

template checkConstraint( T ) {
    template checkConstraint( alias Constraint ) {
        enum checkConstraint = Constraint!T;
    }
}


template constrain( T... ) {
auto constrain( U, string file = __FILE__, int line = __LINE__ )( auto ref U value ) { static assert( allSatisfy!( checkConstraint!U, T ), "Type " ~ U.stringof ~ " does not fulfill the constraints " ~ T.stringof );
        return value;
    }
}

version (unittest) {
    import std.range : isInputRange, ElementType;

    template hasElementType( T ) {
        template hasElementType( U ) {
            enum hasElementType = is( ElementType!U == T );
        }
    }
}
unittest {
assert( __traits( compiles, { int[] a = constrain!isInputRange( [1,2,3] ); } ) ); assert( !__traits( compiles, { int a = constrain!isInputRange( 2 ); } ) ); assert( __traits( compiles, { int[] a = constrain!(isInputRange, hasElementType!int)( [1,2,3] ); } ) ); assert( __traits( compiles, { string a = constrain!(isInputRange, hasElementType!dchar)( "abc" ); } ) ); assert( !__traits( compiles, { string a = constrain!(isInputRange, hasElementType!dchar)( "abc"w ); } ) );
}


So there. Now, you simply use auto a = constrain!isInputRange( expression );. Is this what you wanted?

--
Simen

Reply via email to