op | opfunc |
---|---|
-e | opNeg |
+e | opPos |
~e | opCom |
e++ | opPostInc |
e-- | opPostDec |
cast(type)e | opCast |
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
struct A { int opCast() { return 28; } } void test() { A a; long i = cast(long)a; // i is set to 28L void* p = cast(void*)a; // error, cannot implicitly // convert int to void* int j = a; // error, cannot implicitly convert // A to int }
op | commutative? | opfunc | opfunc_r |
---|---|---|---|
+ | yes | opAdd | opAdd_r |
- | no | opSub | opSub_r |
* | yes | opMul | opMul_r |
/ | no | opDiv | opDiv_r |
% | no | opMod | opMod_r |
& | yes | opAnd | opAnd_r |
| | yes | opOr | opOr_r |
^ | yes | opXor | opXor_r |
<< | 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, and the syntax:
a op bthe following sequence of rules is applied, in order, to determine which form is used:
a.opfunc(b) b.opfunc_r(a)If any a.opfunc or b.opfunc_r functions exist, then overloading is applied across all of them and the best match is used. If either exist, and there is no argument match, then it is an error.
a.opfunc_r(b) 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)
class A { int opAdd(int i); } class B { int opAdd_r(A a); } A a; B b; a + 1; // equivalent to a.opAdd(1) a + b; // equivalent to b.opAdd_r(a) b + a; // equivalent to b.opAdd_r(a)
class A { int opAdd(B b); int opAdd_r(B b); } class B { } A a; B b; a + b; // equivalent to a.opAdd(b) b + a; // equivalent to a.opAdd_r(b)
class A { int opAdd(B b); int opAdd_r(B b); } class B { int opAdd_r(A a); } A a; B b; a + b; // ambiguous: a.opAdd(b) or b.opAdd_r(a) b + a; // equivalent to a.opAdd_r(b)
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 i1, int i2, int i3); int opIndexAssign(int value, int i1, int i2); } void test() { A a; int i; i = a[5,6,7]; // same as i = a.opIndex(5,6,7); a[i,3] = 7; // same as a.opIndexAssign(7,i,3); }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); }