d使用d1的重载操作符
上个月发布的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);//对每一个操作.
}
}
必须别名opBinary至符号.而不是串,因而用mixin(d1).这是相对新的功能.旧版要用mixin在整个别名语句.最新的,相对就好看多了.最终代码:
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;
}
主块代码;
opMod不在类中.
其他D1风格符号
可,另加循环来处理opUnary/opBinaryRight,
还可嵌套映射,或按映射部分,来包含要别名的模板名.opBinaryRight和opBinary,除了在in上外,其余相同.用静每一不易出错.
浙公网安备 33010602011771号