2012-06-09 15 views
7

Czy istnieje możliwość napisania pojedynczej funkcji szablonowej w celu zwiększenia (numerycznych) pól różnych struktur? Na przykład:Parametry szablonu Struct i Tuple w D

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

struct Point 
{ 
    double x, y; 
} 

Próbowałem coś takiego:

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 
} 

Próbowałem również pisanie szablonów funkcyjnych, które akceptują krotki, ale krotki są zawsze rozwinięty, który zapobiega kompilator od dopasowania prawidłowego szablonu . Dzięki.

Odpowiedz

12

Cóż, powiedziałbym, że to, co próbujesz, jest dość dziwne, ale na pewno jest możliwe. Najbardziej naiwny, sposobem na miejscu będzie prawdopodobnie:

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

Najprostszy sposób to zrobić kopię będzie prawdopodobnie go skopiować, a następnie zaktualizować go zamiast próbować skonstruować nowe z zaktualizowanych wartości (choć jestem pewien, że można zrobić zbyt jeśli naprawdę chcesz):

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

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

    return copy; 
} 

głównym problemem tutaj, oczywiście, jest to, że ograniczenie szablon na obu z nich jest zbyt słaby. Wszystko, co musisz zrobić, to mieć niewymienne typy w twojej strukturze i to nie zadziała. Najprostszym sposobem, aby ustalić, że będzie prawdopodobnie do stworzenia tytułowego szablon przetestować go dla Ciebie:

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;})); 
} 

A jeśli chcesz, aby móc zwiększyć wszystkich pól, które są incrementable i zostawić na innych, byłyby prawdopodobnie zrobić coś takiego:

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;})); 
} 

W każdym razie najważniejsze, że wydaje się, że brakowało próba Iterowanie nad tupleof bezpośrednio podczas korzystania ref tak, że elementy zostały zaktualizowane zamiast ich kopie są zaktualizowany.

+1

Niesamowita magia! – YGL

Powiązane problemy