Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mapping variadic template arguments in D

Is there any built-in, or library-provided way to map a set of variadic template arguments in D?

For example:

void foo(Args...)(Args args)
{
    bar(fun(args));
}

I want that to expand to:

void foo(Args...)(Args args)
{
    bar(fun(args[0]), fun(args[1]), fun(args[2]), /* ... */);
}

C++11 variadic templates support this. How do you do the same in D?

like image 703
Peter Alexander Avatar asked Oct 15 '12 01:10

Peter Alexander


2 Answers

Here's an updated version that compiles with recent versions of the D compiler:

/**
    Return a Tuple expression of $(D Func) being
    applied to every tuple argument.
*/
template Map(alias Func, args...)
{
    static auto ref ArgCall(alias Func, alias arg)() { return Func(arg); }

    static if (args.length > 1)
        alias Map = TypeTuple!(ArgCall!(Func, args[0]), Map!(Func, args[1 .. $]));
    else
        alias Map = ArgCall!(Func, args[0]);
}

///
unittest
{
    import std.conv;

    int square(int arg)
    {
        return arg * arg;
    }

    int refSquare(ref int arg)
    {
        arg *= arg;
        return arg;
    }

    ref int refRetSquare(ref int arg)
    {
        arg *= arg;
        return arg;
    }

    void test(int a, int b)
    {
        assert(a == 4, a.text);
        assert(b == 16, b.text);
    }

    void testRef(ref int a, ref int b)
    {
        assert(a++ == 16, a.text);
        assert(b++ == 256, b.text);
    }

    int a = 2;
    int b = 4;

    test(Map!(square, a, b));

    test(Map!(refSquare, a, b));
    assert(a == 4);
    assert(b == 16);

    testRef(Map!(refRetSquare, a, b));
    assert(a == 17);
    assert(b == 257);
}
like image 89
Andrej Mitrović Avatar answered Nov 16 '22 13:11

Andrej Mitrović


This is the best I've come up with:

auto staticMappedCall(alias call, alias F, T...)(T t)
{
    T a;
    foreach(i, arg; t)
            a[i] = F(arg);
    return call(a);
}

You use it like this:

    staticMappedCall!(bar,t)(1, 2);

Where bar is the function to call and t is the transformation.

void bar(int a, int b) { writeln(a, " ", b); }
int t(int a) { return a*2; }

staticMappedCall!(bar, t)(1, 2);

> test
2 4
like image 6
Adam D. Ruppe Avatar answered Nov 16 '22 13:11

Adam D. Ruppe