2012-06-09 29 views
7

Có thể viết một hàm templated đơn lẻ để tăng các trường (số) của các cấu trúc khác nhau không? Ví dụ:Các tham số mẫu Tuple và Cấu trúc trong D

struct Color 
{ 
    ubyte a,r,g,b; 
} 

struct Point 
{ 
    double x, y; 
} 

tôi đã cố gắng một cái gì đó như thế này:

T update(T, A)(T t, A a) 
if (is(T == struct)) 
{ 
    auto vals = t.tupleof; 
    foreach (i; 0 .. vals.length) { 
     vals[i] += a; // error: i cannot be read at compile time 
    } 
    return T(vals); // convert back to struct 
} 

Tôi cũng đã cố gắng viết chức năng mẫu mà chấp nhận tuples, nhưng các bộ luôn được mở rộng, trong đó ngăn chặn các trình biên dịch từ phù hợp với các mẫu đúng . Cảm ơn.

Trả lời

12

Vâng, tôi muốn nói rằng những gì bạn đang cố gắng làm là khá kỳ lạ, nhưng chắc chắn là có thể. Các ngây thơ nhất, tại chỗ cách có lẽ sẽ là:

void update(T)(ref T t) 
    if(is(T == struct)) 
{ 
    foreach(ref var; t.tupleof) 
     ++var; 
} 

Cách đơn giản nhất để làm điều đó với một bản sao có lẽ sẽ để sao chép nó và sau đó cập nhật nó chứ không phải là cố gắng để xây dựng một cái mới với các giá trị được cập nhật (mặc dù tôi chắc chắn rằng điều đó cũng có thể được thực hiện nếu bạn thực sự muốn):

T update(T)(T t) 
    if(is(T == struct)) 
{ 
    auto copy = t; 

    foreach(ref var; copy.tupleof) 
     ++var; 

    return copy; 
} 

Vấn đề chính ở đây, là ràng buộc mẫu trên cả hai yếu tố này quá yếu. Tất cả những gì bạn phải làm là có các loại không thể tách rời trong cấu trúc của bạn và nó sẽ không hoạt động. Cách đơn giản nhất để khắc phục điều đó có lẽ sẽ là để tạo ra một mẫu cùng tên để kiểm tra điều đó cho bạn:

T update(T)(T t) 
    if(isIncrementableStruct!T) 
{ 
    auto copy = t; 

    foreach(ref var; copy.tupleof) 
     ++var; 

    return copy; 
} 

template isIncrementableStruct(T) 
{ 
    enum isIncrementableStruct = is(T == struct) && 
           is(typeof({T t; foreach(var; t.tupleof) ++var;})); 
} 

Và nếu bạn muốn để có thể tăng tất cả các lĩnh vực có incrementable và để lại những người khác một mình, bạn 'd lẽ làm một cái gì đó như:

T update(T)(T t) 
    if(is(T == struct)) 
{ 
    auto copy = t; 

    foreach(ref var; copy.tupleof) 
    { 
     static if(canIncrement!(typeof(var))) 
      ++var; 
    } 

    return copy; 
} 

template canIncrement(T) 
{ 
    enum canIncrement = is(typeof({T var; ++var;})); 
} 

trong mọi trường hợp, điều chính mà bạn dường như đã bỏ qua là để cố gắng iterating qua tupleof trực tiếp trong khi sử dụng ref để các yếu tố đã được cập nhật thay vì phải bản sao của chúng là đã cập nhật.

+1

thuật sĩ tuyệt vời! – YGL

Các vấn đề liên quan