On 12/30/2017 11:00 AM, aliak wrote:

Instead of this:
   auto result = range.op!f;
   if (!result.empty) {
     result.front.method();
   }

This:
   range.op!f.ifFront.method();


In the above scenario I only want method to be called if the pipeline resulted in any element left in the range.

If you're fine with specifying the function as a template argument, the following works. (As seen with 's => s.foo()' below, you have to use a lambda for member functions anyway.)

auto ifFront(alias func, R)(R range) {
    import std.traits : isArray;
    static if (isArray!R) {
        import std.array : empty, front;
    }
    if (!range.empty) {
        func(range.front);
    }
}

unittest {
    size_t executed;

    struct S {
        size_t *e;
        this(ref size_t e) {
            this.e = &e;
        }

        void foo() {
            ++(*e);
        }
    }

    auto foo(int) {
        ++executed;
    }

    // Non-empty array; should be called
    auto a = [1];
    a.ifFront!foo;
    assert(executed == 1);

    // Empty array; should not be called
    int[] b;
    b.ifFront!foo;
    assert(executed == 1);

    // Non-empty S array; should be called
    auto c = [ S(executed) ];
    c.ifFront!(s => s.foo());
    assert(executed == 2);

    // Empty S array; should not be called
    S[] d;
    d.ifFront!(s => s.foo());
    assert(executed == 2);
}

void main() {
}

Ali

Reply via email to