原文
上個月釋出的
2.100
版本語言已完全删除
舊重載
符号.但是,使用D出色的
元程式設計功能
,可以編寫
插件模闆
,來讓
D1
風格
重載符号
繼續工作.
對比D1與D2重載符号
重載
符号用來
自定義
(如+和-)操作符.在
D1
中,是用
普通命名
函數,如加法
opAdd
或乘法
opMul
.示例,用
整
來表示
内部狀态
的結構類型:
struct S {
int x;
S opAdd(S other) {
return S(x + other.x);
}
S opSub(S other) {
return S(x - other.x);
}
S opMul(S other) {
return S(x * other.x);
}
S opDiv(S other) {
assert(other.x != 0, "除零!");
return S(x / other.x);
}//後面簡稱為`四塊代碼`.
}
void main() {//後面簡寫為`主塊代碼`
S s1 = S(6);
S s2 = S(3);
assert(s1 + s2 == S( 9));
assert(s1 - s2 == S( 3));
assert(s1 * s2 == S(18));
assert(s1 / s2 == S( 2));
assert( s1 % s2 == S( 0));
assert((s1 | s2) == S( 7));
//...
}
太多重複代碼.
D2
改進了.
struct S {
int x;
S opBinary(string op)(S other) {
static if(op == "/" || op == "%")
assert(other.x != 0, "除零!");
return mixin("S(x ", op, " other.x)");
}
}
主塊代碼;
注意,僅有
一個函數
(
除法
符号
略有
不同),且處理
所有數學運算
!
代碼
更容易編寫,更不容易
出錯
,也
更簡潔
.
别名符号
struct S {
int x;
四塊代碼;
alias opBinary(op : "+") = opAdd;
alias opBinary(op : "-") = opSub;
alias opBinary(op : "*") = opMul;
alias opBinary(op : "/") = opDiv;
//别名符号.
}
注意,在此使用了
D元程式設計
很酷的特性.
别名
是
同名模闆
,
特化
了模闆參數,并用
模闆限制
過濾.
插件模闆
插件模闆
更是強大.
為了完成它,制定
三個規則
.
1,
不關心
是否按
D1
風格
正确
編寫
操作符
.隻要
名字比對
,就轉發給
他們
.也不擔心
重載
接受的
類型或參數
,因為别名隻是
重寫
名字.
2,該
插件
必須放在
類型
末尾,否則,
編譯器
可能不會分析
整個類型
的成員(未來
D版本
可能改變).
3,
D
禁止
插件和普通
函數間的
重載
,且
普通
函數優先.是以,不要定義有
D2
風格符号的特定名(如
opBinary
).如果想要
D2
符号,則反之.總之,不要混用
D1
和
D2
.
在
插件
模闆中編寫
opAdd
聲明,看看工作原理.
mixin template D1Ops() {
static if(__traits(hasMember, typeof(this), "opAdd"))
alias opBinary(op : "+") = opAdd;
//當有`opadd`時,别名此函數為左邊.
}
這裡有很多
元代碼
,我會一一解釋.
插件模闆
聲明告訴
編譯器
,這是
插件模闆
.技術上,可
插件
任意模闆,但聲明為
插件模闆
,則它隻能用于
插件
.
靜如是條件為真時執行.
__traits(hasMember,T,"opAdd")
是僅當指定
T
類型(這裡
插件
至相應構類型)有
opAdd
成員函數時才為真的
特殊條件
.最後,
别名
和之前寫的一樣.
現在,如何在
類型
中使用它呢?
struct S {
int x;
四塊代碼;
mixin D1Ops;
}
使用别名,可處理現有
重載符号
問題.再借助靜每一擴充.
mixin template D1Ops() {
static foreach(op, d1;
["+" : "opAdd", "-" : "opSub", "*" : "opMul", "/" : "opDiv","%" : "opMod"]) {
//static foreach編譯時疊代普通運作時疊代元素.
static if(__traits(hasMember, typeof(this), d1))
alias opBinary(string s : op) = mixin(d1);//對每一個操作.
}
}
mixin template D1Ops() {
static foreach(op, d1;
["+" : "opAdd", "-" : "opSub", "*" : "opMul", "/" : "opDiv","%" : "opMod"]) {
static if(__traits(hasMember, typeof(this), d1))
alias opBinary(string s : op) = mixin(d1);
}
}
struct S {
int x;
四塊代碼;
mixin D1Ops;
}
主塊代碼;