op | opfunc |
---|---|
- | opNeg |
~ | opCom |
e++ | opPostInc |
e-- | opPostDec |
Given a unary overloadable operator op and its corresponding class or struct member function name opfunc, the syntax:
op awhere a is a class or struct object reference, is interpreted as if it was written as:
a.opfunc()
class A { int opNeg(); } A a; -a; // equivalent to a.opNeg();
class A { int opNeg(int i); } A a; -a; // equivalent to a.opNeg(), which is an error
op | commutative? | opfunc | opfunc_r |
---|---|---|---|
+ | yes | opAdd | - |
- | no | opSub | opSub_r |
* | yes | opMul | - |
/ | no | opDiv | opDiv_r |
% | no | opMod | opMod_r |
& | yes | opAnd | - |
| | yes | opOr | - |
^ | yes | opXor | - |
<< | no | opShl | opShl_r |
>> | no | opShr | opShr_r |
>>> | no | opUShr | opUShr_r |
~ | no | opCat | opCat_r |
== | yes | opEquals | - |
!= | yes | opEquals | - |
< | yes | opCmp | - |
<= | yes | opCmp | - |
> | yes | opCmp | - |
>= | yes | opCmp | - |
+= | no | opAddAssign | - |
-= | no | opSubAssign | - |
*= | no | opMulAssign | - |
/= | no | opDivAssign | - |
%= | no | opModAssign | - |
&= | no | opAndAssign | - |
|= | no | opOrAssign | - |
^= | no | opXorAssign | - |
<<= | no | opShlAssign | - |
>>= | no | opShrAssign | - |
>>>= | no | opUShrAssign | - |
~= | no | opCatAssign | - |
Given a binary overloadable operator op and its corresponding class or struct member function name opfunc and opfunc_r, the syntax:
a op bis interpreted as if it was written as:
a.opfunc(b)or:
b.opfunc_r(a)The following sequence of rules is applied, in order, to determine which form is used:
a.opfunc(b)
b.opfunc_r(a)
b.opfunc(a)
class A { int opAdd(int i); } A a; a + 1; // equivalent to a.opAdd(1)
1 + a; // equivalent to a.opAdd(1)
class B { int opDiv_r(int i); } B b; 1 / b; // equivalent to b.opDiv_r(1)
The member function opEquals() is defined as part of Object as:
int opEquals(Object o);so that every class object has an opEquals().
If a struct has no opEquals() function declared for it, a bit compare of the contents of the two structs is done to determine equality or inequality.
The member function opCmp() is defined as part of Object as:
int opCmp(Object o);so that every class object has a opCmp().
If a struct has no opCmp() function declared for it, attempting to compare two structs is an error.
Note: Comparing a reference to a class object against null should be done as:
if (a === null)and not as:
if (a == null)The latter is converted to:
if (a.opCmp(null))which will fail if opCmp() is a virtual function.
class A { int opCmp(Object o) { assert(0); // comparison makes no sense return 0; } }
struct F { int opCall(); int opCall(int x, int y, int z); } void test() { F f; int i; i = f(); // same as i = f.opCall(); i = f(3,4,5); // same as i = a.opCall(3,4,5); }In this way a struct or class object can behave as if it were a function.
struct A { int opIndex(int i); int opIndex(int i, int value); } void test() { A a; int i; i = a[5]; // same as i = a.opIndex(5); a[i] = 7; // same as a.opIndex(i,7); }In this way a struct or class object can behave as if it were an array.
Note: Array index overloading currently does not work for the lvalue of an op=, ++, or -- operator.
class A { int opSlice(); // overloads a[] int opSlice(int x, int y); // overloads a[i .. j] } void test() { A a = new A(); int i; i = a[]; // same as i = a.opSlice(); i = a[3..4]; // same as i = a.opSlice(3,4); }