operator overloading - sencillos - Elegante sobrecarga del operador en D
sobrecarga de operadores c++ pdf (2)
Durante un tiempo estuve confundido acerca de la dirección de la sobrecarga del operador de D, pero ahora me doy cuenta de que es un sistema hermoso ... si solo funcionara con los tipos de núcleo (int, float, etc.). Considere el siguiente código:
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
}
}
Este sería un código hermoso si funcionara, ya que sobrecarga a todos los operadores + =, - =, * =, etc. en un solo método. Sin embargo, como puede ver, no funciona fuera de la caja. He creado una solución usando plantillas (god I love 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);
}
}
Esto está bien, solo que preferiría mantener todo "en casa". ¿Hay alguna manera de hacer que esto funcione sin la ayuda de una plantilla? Sé que estoy siendo delicado aquí, ya que no hay pérdida de rendimiento y no es difícil importar un módulo en la situación que necesito para hacer esto. Me pregunto si está integrado y estoy pasando por alto algo.
Casi todos los operadores sobrecargados en D son plantillas por definición . Tenga en cuenta que void opOpAssign(string op)(Vector vector)
tiene un parámetro de plantilla que es una cadena. Entonces, no, no puedes sobrecargarlo como una función que no es de plantilla. Ahora, no necesita una segunda plantilla para hacerlo (por lo tanto, si al preguntarle si necesita una plantilla, quiere decir una plantilla auxiliar, la respuesta es no), pero la función del operador sobrecargado ya es una plantilla.
La forma canónica de hacer lo que estás tratando de hacer aquí es usar combinaciones de cadenas:
void opOpAssign(string op)(Vector vector)
{
mixin("X" ~ op ~ "=vector.X;");
mixin("Y" ~ op ~ "=vector.Y;");
}
esto está destinado a ser combinado con mixins
void opOpAssign(string op)(Vector vector) {
mixin("X"~op~"=vector.X;");
mixin("Y"~op~"=vector.Y;");
}
Sin mencionar que esto puede ser fácilmente acoplado a otras operaciones aritméticas.
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 incluso a otras escalas del Vector.
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;
}
tenga en cuenta que el opBinary
s definido restringe lo que se puede pasar a opOpAssign
pero puede ir en ambos sentidos (defina opBinary
en términos de opOpAssign
)