struct DVECTOR2 { // Controls that the parameter is a valid type template Accepts(T) { enum Accepts = is(T == DVECTOR2) || is(T == float) || is(T == D3DXVECTOR2) || is(T == POINT); } // Whether the parameter is a float or not template isScalar(T) { enum isScalar = is(T == float); } // The Variables float x = 0f; float y = 0f; // Default Constructor this()(float x, float y) { this.x = x; this.y = y; } // Float Constructor this()(float xy) { this(xy, xy); } // Implement D3DXVECTOR2 and POINT support this(T)(T arg) if(Accepts!T && !isScalar!T) { this(arg.tupleof); } // Inverse the vector DVECTOR2 opUnary(string op)() if(op == "-") { return DVECTOR2(-x, -y); } // Binary Operations DVECTOR2 opBinary(string op, T)(T rhs) if(Accepts!T) { enum rx = isScalar!T ? "" : ".x"; enum ry = isScalar!T ? "" : ".y"; return DVECTOR2(mixin("x" ~ op ~ "rhs" ~ rx), mixin("y" ~ op ~ "rhs" ~ ry)); } // Right Binary Operator DVECTOR2 opBinaryRight(string op, T)(T lhs) if(Accepts!T) { return DVECTOR2(lhs).opBinary!op(this); } // Assign Operator ref DVECTOR2 opAssign(T)(T rhs) if(Accepts!T) { static if(isScalar!T) x = y = rhs; else { x = rhs.x; y = rhs.y; } return this; } // In-Place Assignment Operators ref DVECTOR2 opOpAssign(string op, T)(T rhs) if(Accepts!T) { return(this.opAssign(opBinary!op(rhs))); } // Cast Operators (to D3DXVECTOR2 and POINT) T opCast(T)() if(Accepts!T && !isScalar!T) { return T(x, y); } } unittest { // This fails, saying that the expression cannot be // evaluated at compile time. immutable DVECTOR2 test = DVECTOR2(0f, 1f, 0f); }