2012-10-15 12 views
7

Esiste un modo incorporato o fornito dalla libreria per mappare un insieme di argomenti modello variadic in D?Mappatura degli argomenti del modello variadico in D

Ad esempio:

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

voglio che a espandere a:

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

C++ 11 modelli variadic supportano questa. Come fai lo stesso in D?

risposta

6

Questo è il migliore che è venuta in mente:

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

Si utilizza in questo modo:

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

Dove bar è la funzione di chiamare e t è la trasformazione.

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

in realtà che non necessariamente funziona se la trasformata di funzione restituisce un tipo diverso. Ma se hai fatto import std.traits; ParameterTypeTuple! Chiama a; piuttosto che T a ;, penso che lo farebbe. –

+0

C'è un altro problema: non funziona quando T contiene tipi immutabili. Penso che l'unico modo per farlo bene è usare i mixin di stringhe. Sto lavorando a una richiesta di pull per Phobos ora. –

+0

La mia implementazione funziona con tipi con campi immutabili: http://stackoverflow.com/a/12926873/279684 –

7

Ecco una versione aggiornata che si compila con le recenti versioni del compilatore 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); 
} 
Problemi correlati