2012-06-09 8 views
7

È possibile scrivere una singola funzione basata su modelli per incrementare i campi (numerici) di diverse strutture? Per esempio:Parametri modello di struttura e tupla in D

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

struct Point 
{ 
    double x, y; 
} 

Ho provato qualcosa di simile:

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 
} 

Ho anche provato a scrivere modelli funzionali che accettano tuple, ma le tuple sono sempre espansi, che impedisce al compilatore di corrispondenza il modello corretto . Grazie.

risposta

12

Bene, direi che quello che stai cercando di fare è piuttosto bizzarro, ma è certamente possibile. Il, in-place modo più ingenuo sarebbe probabilmente:

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

Il modo più semplice per farlo con una copia probabilmente sarebbe copiarlo e poi aggiornarlo piuttosto che cercare di costruire una nuova con valori aggiornati (anche se sono sicuro che questo può essere fatto anche se si vuole veramente):

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

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

    return copy; 
} 

il problema principale, naturalmente, è che il vincolo modello su entrambi questi è troppo debole. Tutto quello che devi fare è avere tipi non ricorrenti nella tua struct, e non funzionerà. Il modo più semplice per risolvere il problema che probabilmente sarebbe di creare un modello omonimo per testarlo per voi:

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

E se si vuole essere in grado di incrementare tutti i campi che sono incrementabile e lasciare in pace gli altri, 'd probabilmente fare qualcosa di simile:

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

In ogni caso, la cosa principale che si sembrano aver perso è stato quello di tentare l'iterazione su tupleof direttamente durante l'utilizzo ref in modo che gli elementi sono stati aggiornati, piuttosto che avere copie di loro che sono aggiornato.

+1

incredibile magia! – YGL

Problemi correlati