How do you safely deal with range.front?

Ali Çehreli acehreli at yahoo.com
Mon Jan 1 04:18:29 UTC 2018


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


More information about the Digitalmars-d-learn mailing list