2012-10-15 17 views
7

Có cách nào được xây dựng trong thư viện hoặc cung cấp thư viện để ánh xạ một tập hợp các đối số mẫu của biến thể trong D không?Lập bản đồ các đối số mẫu có định dạng trong D

Ví dụ:

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

Tôi muốn điều đó mở rộng đến:

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

C++ 11 mẫu variadic hỗ trợ này. Làm thế nào để bạn làm tương tự trong D?

Trả lời

6

Đây là tốt nhất mà tôi đã đi lên với:

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

Bạn sử dụng nó như thế này:

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

đâu thanh là chức năng gọi và t là việc chuyển đổi.

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

thực sự sẽ không nhất thiết phải làm việc nếu biến đổi hàm trả về một kiểu khác nhau. Nhưng nếu bạn đã thực hiện nhập std.traits; ParameterTypeTuple! Gọi a; thay vì T a ;, tôi nghĩ điều đó sẽ thực hiện. –

+0

Có một vấn đề khác: nó không hoạt động khi T chứa các loại bất biến. Tôi nghĩ cách duy nhất để làm điều này là sử dụng mixin chuỗi. Tôi đang thực hiện yêu cầu kéo cho Phobos ngay bây giờ. –

+0

Triển khai của tôi hoạt động với các loại có các trường không thể thay đổi được: http://stackoverflow.com/a/12926873/279684 –

7

Dưới đây là một phiên bản cập nhật đó biên dịch với các phiên bản gần đây của trình biên dịch 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); 
} 
Các vấn đề liên quan