原文
上个月发布的
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;
}
主块代码;