On Sunday, 16 August 2015 at 11:53:42 UTC, FreeSlave wrote:
Let's say I want to map some range using some context.
The obvious way is to do:

uint[3] arr = [1,2,3];
uint context = 2;
auto r = arr[].map!(delegate(value) { return value * context; });

The problem is that this allocates delegate, so it can't be used in @nogc code.
What I want to do might look like this:

static struct Caller
{
    this(uint context) @nogc {
        _context = context;
    }
    auto opCall(uint value) @nogc {
        return value * _context;
    }
    uint _context;
}

auto caller = Caller(2);
auto r = arr[].map!(&caller.opCall);

But it will not work of course since function must be a compile-time parameter.

So the way to go would be:

auto caller = Caller(2);
auto r = arr[].map!(Caller.opCall)(&caller);

But map and other algorithms don't support this interface.

The other way is

auto r = arr.map!(Caller(2));

But again, since it's template parameter, it can't use variables unknown at compile time:

uint context = ...;
auto r = arr.map!(Caller(context)); //will not work

So what's the solution? Of course besides rewriting the whole std.algorithm.

Ok, so as my lambda proposition obviously doesn't work, here is one way that does using a templated function. There may be a way to make it shorter, I don't know.


    import std.conv;
    import std.stdio;

    template fun(uint context) {
        static uint withContext(uint value) {
            return value * context;
        }

        auto fun(uint[] arr) @nogc {
            return arr.map!withContext;
        }
    }

    void main(string[] args) {
        [1, 2, 3].to!(uint[])
                 .fun!2
                 .writeln;
    }

Reply via email to