Operator Overloading
-a, ++a, ~a, *a opBinary!"op", opBinaryRight!"op" a < b, <=,...
a[i], a[i] = v, a[i] += v opIndex, opIndexAssign, opIndexOpAssign a[i.. j], $ opSlice, opDollar foreach (x; a) opApply (or range primitives)
struct Vec2
{
double x, y;
Vec2 opBinary(string op)(Vec2 rhs) const if (op == "+" || op == "-")
{
return mixin("Vec2(x " ~ op ~ " rhs.x, y " ~ op ~ " rhs.y)");
}
Vec2 opBinary(string op : "*")(double k) const { return Vec2(x * k, y * k); }
Vec2 opBinaryRight(string op : "*")(double k) const { return this * k; } // k * v
Vec2 opUnary(string op : "-")() const { return Vec2(-x, -y); }
ref Vec2 opOpAssign(string op)(Vec2 rhs) { mixin("x " ~ op ~ "= rhs.x; y " ~ op ~ "= rhs.y;"); return this; }
bool opEquals(const Vec2 o) const { return x == o.x && y == o.y; }
int opCmp(const Vec2 o) const { import std.math : cmp; return cmp(x * x + y * y, o.x * o.x + o.y * o.y); }
double opIndex(size_t i) const { return i == 0 ? x : y; }
void opIndexAssign(double v, size_t i) { if (i == 0) x = v; else y = v; }
T opCast(T : bool)() const { return x != 0 || y != 0; }
double opCall() const { import std.math : sqrt; return sqrt(x * x + y * y); } // v()
size_t toHash() const nothrow @safe { return hashOf(x) ^ hashOf(y); }
}struct Tree
{
int[] data;
int opApply(scope int delegate(ref int) dg) // custom foreach iteration
{
foreach (ref x; data) if (auto r = dg(x)) return r;
return 0;
}
}