22用d編程重載運算符

對類,不能重載opAssign,因爲是按引用的.賦值是引用.
重載運算符,主要是爲了方便書寫.

struct TimeOfDay {
// ...
    ref TimeOfDay opOpAssign(string op)(in Duration duration)//(1)
            if (op == "+") {                                 //(2)
        minute += duration.minute;
        hour += minute / 60;
        minute %= 60;hour %= 24;
        return this;//本爲引用?
    }
}

opOpAssign(string op),表示是賦值大類下面的重載
opOpAssign!"+"就是+=符的重載,注意,返回的是引用.
c++不一樣,c++是指針.而d引用.
要注意,重載的函數的語義最好是直觀的,不要瞎搞.
可重載的操作符有:
一元操作符:

操作符 意思
-對象 取反 “-”
+對象 與+一樣 “+”
~對象 按位取反 “~”
*對象 訪問指針 “*”
++對象 加1 “++”
--對象 減1 “–”

不能自定義後++與後--,編譯器給你搞
二元操作符:
+ - * / % ^^ & ^ << >> >>> ~ in == != < <= > >= = += -= *= /= %= ^^= &= ^= <<= >>= >>>= ~=
有兩種:
x 操作 y,

x.opBinary!"op"(y);
y.opBinaryRight!"op"(x);
函數名 示例
opIndex 集合[i]
opIndexAssign 集合[i] = 7
opIndexUnary ++集合[i]
opIndexOpAssign 集合[i] *= 2
opDollar 集合[$ - 1]
opSlice 集合[]
opSlice(正,正) 集合[i…j]

還有opCall((...)),opCast(轉!...),opDispatch(未知函數)

struct Duration {
    int minute;

    ref Duration opUnary(string op)()
            if ((op == "++") || (op == "--")) {
        mixin (op ~ "minute;");
        return this;
    }

    ref Duration opOpAssign(string op)(in int amount)
            if ((op == "+") || (op == "-")) {
      //(op == "*") || (op == "/")) {//擴展
        mixin ("minute " ~ op ~ "= amount;");
        return this;
    }
    ref Duration opOpAssign(string op)(in int amount)
//不要限制了.
        mixin ("minute " ~ op ~ "= amount;");
        return this;
    }
}
  int i = 1;
    writeln(":", &i);
    writeln(":", &(++i));
//看看地址

修改自身的有opUnary!"++", opUnary!"--"所有opOpAssign重載.
opEquals,必須返回
in一般返回對象,也可返回.
表示<, <=, >, 和 >=opCmp返回
創建新對象的操作符:一元-, +, ~;二元~.及
算術操作:+, -, 星, /, %, 和 ^^,
按位操作&, |, ^, <<, >>, 和 >>>opAssign,有時op賦值會返回常 引用(鑰匙).而不是實體.
opDollar返回容器元素個數
未限制操作符:
一元 星, opCall, opCast, opDispatch, opSlice, 和所有opIndex
opEquals 和 opCmp必須一致,如果相等,則比較必須爲0.一般可以不定義相等操作,編譯器自動生成.
有些需要不同的相等定義,可以定義一個.
opCmp用於排序.可以控制<,<=,>,>=,返回類型爲.
如左在右前,則返回負,左在右後,返回正.相等爲0.

 int opCmp(in TimeOfDay rhs) const {
        return (hour == rhs.hour
                ? minute - rhs.minute
                : hour - rhs.hour);
    }//注意,減號可能導致溢出.
struct S {
    int i;

    int opCmp(in S rhs) const {
        return i - rhs.i;          // 漏洞
    }//-2比`最大整更大`?.
}

void main() {
    assert(S(-2) > S(int.max));    // 錯誤排序
}
//算法改進
import std.algorithm;

struct S {
    string name;
    int opCmp(in S rhs) const {
        return cmp(name, rhs.name);//字母序比較
    }
}

opCall()用於調用函數.
static opCall(),用來靜態創建默認()
定義opCall()禁止了編譯器自動生成的構造函數
因此這樣用:

struct LinearEquation {
    double a;
    double b;

    double opCall(double x) const {
        return a * x + b;
    }
}
//這樣用
   LinearEquation equation = { 1.2, 3.4 };
    double y = equation(5.6);//像函數一樣使用

下面是個雙端隊列

import std.stdio;
import std.string;
import std.conv;

struct DoubleEndedQueue //也叫雙列
{
private:

    int[] head;    //頭列
    int[] tail;    //尾列

    ref inout(int) elementAt(size_t index) inout {
        return (index < head.length
                ? head[$ - 1 - index]
                : tail[index - head.length]);
    }//實際切片

public:

    string toString() const {
        string result;

        foreach_reverse (element; head) {
            result ~= format("%s ", to!string(element));
        }

        foreach (element; tail) {
            result ~= format("%s ", to!string(element));
        }

        return result;
    }

    version (none) {//tostring的簡單有效實現
    void toString(void delegate(const(char)[]) sink) const {
        import std.format;
        import std.range;

        formattedWrite(//格式寫
            sink, "%(%s %)", chain(head.retro, tail));
    }}

    void insertAtHead(int value) {
        head ~= value;
    }//加元素,加至頭

    ref DoubleEndedQueue opOpAssign(string op)(int value)
            if (op == "~") {
        tail ~= value;
        return this;
    }//加至尾

    inout(int) opIndex(size_t index) inout {
        return elementAt(index);
    }//[]操作

    int opIndexUnary(string op)(size_t index) {
        mixin ("return " ~ op ~ "elementAt(index);");
    }//一元式

    int opIndexAssign(int value, size_t index) {
        return elementAt(index) = value;
    }
    int opIndexOpAssign(string op)(int value, size_t index) {
        mixin ("return elementAt(index) " ~ op ~ "= value;");
    }//[i]+=右

    size_t opDollar() const {
        return head.length + tail.length;
    }
}

void main() {
    auto deque = DoubleEndedQueue();

    foreach (i; 0 .. 10) {
        if (i % 2) {
            deque.insertAtHead(i);

        } else {
            deque ~= i;
        }
    }
    writefln("[3]元素: %s",deque[3]);//訪問元素
    ++deque[4];            // 加元素
    deque[5] = 55;         // 給元素賦值
    deque[6] += 66;        // 加至元素

    (deque ~= 100) ~= 200;

    writeln(deque);
}

(deque ~= 100) ~= 200;因爲,~=爲引用類型.

    deque[] *= 10;    //每個元素*

    // 等價於
    {
        auto range = deque.opSlice();
        range.opOpAssign!"*"(10);//區間切片再*
    }

再如:

import std.exception;

struct DoubleEndedQueue {
// ...
    inout(Range) opSlice() inout {//返回區間
        return inout(Range)(head[], tail[]);
    }

    inout(Range) opSlice(size_t begin, size_t end) inout {//區間[頭..尾]
        enforce(end <= opDollar());
        enforce(begin <= end);
        if (begin < head.length) {
            if (end < head.length) {//區間全在頭內
                return inout(Range)(head[$ - end .. $ - begin],[]);
            } else {//部分在頭,部分在尾
                return inout(Range)(head[0 .. $ - begin],tail[0 .. end - head.length]);
            }
        } else {//完全在尾
            return inout(Range)([],tail[begin - head.length .. end - head.length]);
        }
    }

    struct Range {//區間細節
        int[] headRange,tailRange;
        Range opUnary(string op)() {//一元操作
            mixin (op ~ "headRange[];");
            mixin (op ~ "tailRange[];");
            return this;
        }

        Range opAssign(int value) {//賦值
            headRange[] = value;
            tailRange[] = value;return this;
        }

        Range opOpAssign(string op)(int value) {
            mixin ("headRange[] " ~ op ~ "= value;");
            mixin ("tailRange[] " ~ op ~ "= value;");
            return this;
        }//賦值操作
    }
}

void main() {
    auto deque = DoubleEndedQueue();
    foreach (i; 0 .. 10) {
        if (i % 2) deque.insertAtHead(i);
        else {deque ~= i;}
    }

    writeln(deque);deque[] *= 10;
    deque[3 .. 7] = -1;writeln(deque);
}

opCast轉換類型,是個模板.
opDispatch,最後的調用.包攬所有.

import std.stdio;
import std.conv;

struct Duration {
    int hour;
    int minute;

    double opCast(T : double)() const {
        return hour + (to!double(minute) / 60);
    }//可按這種方式轉成`雙精`
    bool opCast(T : bool)() const {
        return (hour != 0) || (minute != 0);
    }//邏輯表達式中,可以自動調用這個轉換.
}//而其他轉換,得顯式調用.

void main() {
    auto duration = Duration(2, 30);
    double d = to!double(duration);
    writeln(d);
}
void foo(bool b) {
    // ...
}
    foo(duration);//不行,編譯不過
    bool b = duration;//不行,編譯不過

暴力指派函數,最後的函數.

import std.stdio;

struct Foo {
    void opDispatch(string name, T)(T parameter) {
        writefln("Foo.opDispatch - name: %s, value: %s",name, parameter);
    }
}

void main() {
    Foo foo;
    foo.aNonExistentFunction(42);
    foo.anotherNonExistentFunction(100);
}

還有二元的:opBinaryRight!“in”

 if (time in lunchBreak) {
//等價於
if (lunchBreak.opBinaryRight!"in"(time)) {
//應該叫in的右二元操作
//-----
import std.stdio;
import std.string;
struct Duration {int minute;}

struct TimeOfDay {
    int hour;int minute;

    ref TimeOfDay opOpAssign(string op)(in Duration duration)
            if (op == "+") {
        minute += duration.minute;
        hour += minute / 60;
        minute %= 60;hour %= 24;
        return this;
    }

    int opCmp(in TimeOfDay rhs) const {
        return (hour == rhs.hour
                ? minute - rhs.minute
                : hour - rhs.hour);
    }

    string toString() const {
        return format("%02s:%02s", hour, minute);
    }
}

struct TimeSpan {
    TimeOfDay begin;
    TimeOfDay end;    // 尾端

    bool opBinaryRight(string op)(TimeOfDay time) const
            if (op == "in") {
        return (time >= begin) && (time < end);
    }
}

void main() {
    auto lunchBreak = TimeSpan(TimeOfDay(12, 00),
                               TimeOfDay(13, 00));

    for (auto time = TimeOfDay(11, 30);
         time < TimeOfDay(13, 30);
         time += Duration(15)) {

        if (time in lunchBreak) {
            writeln(time, " 吃飯時間");

        } else {
            writeln(time, " 工作時間");
        }
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章