2012-10-15 35 views
7

是否有任何內置或庫提供的方法來映射D中的一組可變參數模板參數?在D中映射可變參數模板參數

例如:

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

我想,要擴大到:

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

C++ 11可變參數模板支持這一點。你如何在D中做同樣的事情?

回答

6

這是我想出來的最好的:

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

你使用這樣的:

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

凡酒吧是要調用的函數,t是轉型。

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

實際上如果轉換函數返回一個不同類型不一定會工作。但是如果你做了 import std.traits; ParameterTypeTuple!call a; 而不是T a;我認爲那樣做。 –

+0

還有一個問題:當T包含不可變類型時它不起作用。我認爲唯一的方法就是使用string mixins。我現在正在爲Phobos提出拉請求。 –

+0

我的實現適用於具有不可變字段的類型:http://stackoverflow.com/a/12926873/279684 –

7

這裏有一個更新的版本與最新版本的編譯器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); 
}