El objetivo es lograr el mismo efecto que en this C++ example: evitar la creación de temporales. Intenté traducir el ejemplo de C++ a D sin éxito. También probé diferentes enfoques.Plantillas de expresión en D
import std.datetime : benchmark;
import std.stdio : writefln, writeln;
void bench(alias fun, string time = "msecs")(string msg, uint n = 1_000_000) {
auto b = benchmark!fun(n);
writefln(" %s: %s ms", msg, b[0].to!(time, int));
}
alias double Real;
struct Expression(string op, E1, E2) {
E1 _v1;
E2 _v2;
alias _v1 v1;
alias _v2 v2;
auto opIndex(size_t i) {
return mixin("v1[i]" ~ op ~ "v2[i]");
}
auto opBinary(string op, E)(auto ref E e) {
return Expression!(op, typeof(this), E)(this, e);
}
}
struct ExpVector {
Real[40] _data = void;
alias _data this;
this(Real datum) pure nothrow { _data = datum; }
auto opBinary(string op, T)(auto ref T other) {
return Expression!(op, typeof(this), T)(this, other);
}
void opAssign(E)(auto ref E exp) {
foreach(i, ref datum; _data)
datum = exp[i];
}
}
struct Vector {
Real[40] _data = void;
alias _data this;
this(Real datum) pure nothrow { _data = datum; }
auto opBinary(string op)(auto ref Vector other) {
Vector ret;
foreach(i, datum; _data)
ret[i] = mixin("datum" ~ op ~ "other[i]");
return ret;
}
}
void main() {
ExpVector e1 = ExpVector(1.5);
ExpVector e2 = ExpVector(7.3);
ExpVector ef;
void T1() {
ef = (e1 + e2) * (e1 + e2);
}
bench!T1(" vector operations using template expression");
Vector v1 = Vector(1.5);
Vector v2 = Vector(7.3);
Vector vf;
void T2() {
vf = (v1 + v2) * (v1 + v2);
}
bench!T2(" regular vector operations");
void T3() {
for(int i = 0; i < vf.length; ++i)
vf[i] = (v1[i] + v2[i]) * (v1[i] + v2[i]);
}
bench!T3(" what is expected if template expressions worked and temporaries were not created.");
}
La versión de la plantilla de expresión es más lenta que la versión de la plantilla de no expresión. Esperaba que la versión de la plantilla de expresión fuera mucho más rápida y cercana a lo esperado. Entonces, ¿qué pasa con mis plantillas de expresión? ¿Cuál es la forma correcta de hacer plantilla de expresión en D?
Bueno, sin siquiera considerar lo que hace el código, quisiera señalar que Tendría que compilar el código en un compilador que comparte un backend con el compilador de C++ para poder realmente comparar el lenguaje en lugar de la implementación del compilador. Si usa gdc para las cosas D y gcc para las cosas C++, obtendrá una mejor comparación del lenguaje en sí. El código D podría ser más lento simplemente porque el motor de dmd no se optimiza tan bien como el de gcc. Podría ser más que eso, pero comparar dmd vs gcc podría ser simplemente comparar los optimizadores de los dos compiladores. –
Creo que ha entendido mal lo que dije. El código que he publicado es más de dos veces más lento que la versión sin plantilla de expresión, es decir, solo una estructura 'Vector' regular que implementa la función de miembro' opBinary', con ambas versiones compiladas con DMD. No lo estoy comparando con el código C++ en Wikipedia. – Arlen
Luego debe publicar ambas versiones. Es difícil comparar algo con otra cosa cuando solo tienes uno de los dos. –