d使用d1的重载操作符

原文

上个月发布的2.100版本语言已完全删除旧重载符号.但是,使用D出色的元编程功能,可以编写插件模板,来让D1风格重载符号继续工作.

对比D1D2重载符号

重载符号用来自定义(如+和-)操作符.在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符号,则反之.总之,不要混用D1D2.
插件模板中编写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,
还可嵌套映射,或按映射部分,来包含要别名的模板名.opBinaryRightopBinary,除了在in上外,其余相同.用静每一不易出错.

posted @   zjh6  阅读(20)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示