2012-10-15 27 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); 
}