2012-10-15 19 views
7

Czy istnieje jakiś wbudowany lub udostępniony w bibliotece sposób mapowania zestawu argumentów szablonu variadic w D?Mapowanie argumentów szablonu variadic w D

Na przykład:

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

Chcę, aby rozwinąć do:

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

C++ 11 o zmiennej liczbie argumentów szablony wspierać. Jak to zrobić w D?

Odpowiedz

6

Jest to najlepszy jaki wymyślić:

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

go używać tak:

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

gdzie jest bar funkcję, aby zadzwonić i t jest transformacja.

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

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

> test 
2 4 
+0

faktycznie, że niekoniecznie będzie działać, jeśli przekształcić zwraca innego typu. Ale jeśli zrobiłeś import std.traits; ParameterTypeTuple! Call a; zamiast T a ;, myślę, że to by to zrobiło. –

+0

Jest inny problem: nie działa, gdy T zawiera typy niezmienne. Myślę, że jedynym sposobem na to, aby to zrobić, jest użycie mixiny. Pracuję teraz nad żądaniem odciągnięcia dla Phobosa. –

+0

Moja implementacja działa z typami z niezmiennymi polami: http://stackoverflow.com/a/12926873/279684 –

7

Oto uaktualniona wersja kompiluje z ostatnich wersji kompilatora D:

/** 
    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); 
}