2011-10-19 10 views
19

Per un po 'sono stato confuso dalla direzione del sovraccarico dell'operatore di D, ma ora mi rendo conto che è un sistema bellissimo ... se funzionasse solo con i tipi di core (int, float, ecc.). Si consideri il codice seguente:Elegante sovraccarico dell'operatore in D

struct Vector { 
    float X, Y; 

    void opOpAssign(string op)(Vector vector) { 
     X.opOpAssign!op(vector.X); // ERROR: no property "opOpAssign" for float 
     Y.opOpAssign!op(vector.Y); // ERROR: ditto 
    } 
} 

Questo sarebbe il codice bello se ha funzionato, visto che sovraccarica tutto + =, - =, * =, ecc .. operatori in un metodo. Tuttavia, come puoi vedere, non funziona immediatamente. Ho creato una soluzione utilizzando i modelli (dio amo D):

template Op(string op, T) { 
    void Assign(ref T a, T b) { 
     static if (op == "+") a += b; 
      else if (op == "-") a -= b; 
      else if (op == "*") a *= b; 
      else if (op == "/") a /= b; 
    } 
} 

struct Vector { 
    float X, Y; 

    void opOpAssign(string op)(Vector vector) { 
     Op!(op, typeof(X)).Assign(X, vector.X); 
     Op!(op, typeof(Y)).Assign(Y, vector.Y); 
    } 
} 

Questo va bene, solo mi piacerebbe molto preferiscono tenere tutto "in casa". C'è un modo per farlo funzionare senza l'ausilio di un modello? So che sono schizzinoso qui, visto che non ci sono perdite di prestazioni e non è difficile importare un modulo in una situazione che devo fare. Mi sto solo chiedendo se è integrato e sto trascurando qualcosa.

+0

Si noti che 'if' statico non è continuato a seguire' 'if's dopo else'. Devi ripetere 'static' di nuovo. – Bolpat

risposta

21

Quasi tutti gli operatori di overload in D sono modelli per definizione. Si noti che void opOpAssign(string op)(Vector vector) ha un parametro modello che è una stringa. Quindi, no non è possibile sovraccaricarlo come una funzione non modello. Ora, non è necessario un secondo modello per farlo (quindi se chiedendo se è necessario un modello, si intende un modello di supporto, quindi la risposta è no), ma la funzione di operatore sovraccarico è già un modello.

Il modo canonico di fare ciò che si sta cercando di fare qui è di usare mixins stringa:

void opOpAssign(string op)(Vector vector) 
{ 
    mixin("X" ~ op ~ "=vector.X;"); 
    mixin("Y" ~ op ~ "=vector.Y;"); 
} 
+0

Accidenti che è stato veloce! Grazie! –

13

questo è destinato a essere combinato con mixins

void opOpAssign(string op)(Vector vector) { 
    mixin("X"~op~"=vector.X;"); 
    mixin("Y"~op~"=vector.Y;"); 
} 

non parlare questo può essere facilmente accoppiato ad altre operazioni aritmetiche

Vector opBinary(string op)(Vector l)if(op=="+"||op=="-"){//only addition and subtraction makes sense for 2D vectors 
    mixin("return Vector(x"~op~"l.x,y"~op~"l.y;"); 
} 

///take in anything as long as a corresponding binaryOp exists 
///this essentially rewrites all "vec op= variable;" to "vec = vec op variable;" 
void opOpAssign(string op,T)(T l){ 
    this = this.binaryOp!op(l); 
} 

e anche ad altri scalare il vettore

Vector opBinary(string op)(real l)if(op=="*"||op=="/"){ 
    mixin("return Vector(x"~op~"l,y"~op~"l;"); 
} 

Vector opBinaryRight(string op)(real l)if(op=="*"){// for 2 * vec 
    return this*l; 
} 

nota che il numero definito opBinary s limita ciò che può essere passato a opOpAssign ma si può andare in entrambe le direzioni (definire opBinary in termini di opOpAssign)

+0

Johnathan ha postato per primo e ha spiegato di più, quindi ho contrassegnato la sua come risposta, ma vorrei ringraziarvi per aver risposto così rapidamente! –

+0

@FiL controlla la mia modifica per un po 'più di bontà. –