D语言中优雅的运算符重载

20

有一段时间,我对D语言中运算符重载的方向感到困惑,但现在我意识到这是一个美妙的系统......只要它能够与核心类型(int、float等)一起使用。考虑以下代码:

struct Vector {
    float X, Y;

    void opOpAssign(string op)(Vector vector) {
        X.opOpAssign!op(vector.X); // ERROR: no property "opOpAssign" for float
        Y.opOpAssign!op(vector.Y); // ERROR: ditto
    }
}

如果它能够正常工作,那么这将是一段美妙的代码,因为它在一个方法中重载了所有 +=、-=、*= 等运算符。但是,正如您所看到的,它并不能直接运行。我已经使用模板创建了一个解决方案(天哪,我爱 D 语言):
template Op(string op, T) {
    void Assign(ref T a, T b) {
        static if (op == "+") a += b;
          else if (op == "-") a -= b;
          else if (op == "*") a *= b;
          else if (op == "/") a /= b;
    }
}

struct Vector {
    float X, Y;

    void opOpAssign(string op)(Vector vector) {
        Op!(op, typeof(X)).Assign(X, vector.X);
        Op!(op, typeof(Y)).Assign(Y, vector.Y);
    }
}

这很好,但我更喜欢将所有内容“内部处理”。有没有方法可以在不使用模板的情况下使其工作?我知道我在挑剔,因为没有性能损失,并且在需要这样做的情况下导入模块并不困难。我只是想知道它是否内置在其中,而我忽略了某些东西。


请注意,static ifelse之后不会继续执行后面的if。您必须再次重复static - Bolpat
2个回答

22
在D语言中,几乎所有的重载运算符都是模板,这是由定义所决定的。请注意,void opOpAssign(string op)(Vector vector)中有一个字符串模板参数。因此,你不能将它重载为非模板函数。现在,你不需要第二个模板来完成它(所以如果你问是否需要一个辅助模板,答案是不需要),因为已经有了重载的运算符函数作为模板。
在这里做你试图做的事情的规范方式是使用字符串混合。
void opOpAssign(string op)(Vector vector)
{
    mixin("X" ~ op ~ "=vector.X;");
    mixin("Y" ~ op ~ "=vector.Y;");
}

13

这是用来与混合器结合使用的

void opOpAssign(string op)(Vector vector) {
    mixin("X"~op~"=vector.X;");
    mixin("Y"~op~"=vector.Y;");
}

更不用说这可以轻松地与其他算术运算相结合。
Vector opBinary(string op)(Vector l)if(op=="+"||op=="-"){//only addition and subtraction makes sense for 2D vectors
    mixin("return Vector(x"~op~"l.x,y"~op~"l.y;");
}

///take in anything as long as a corresponding binaryOp exists
///this essentially rewrites all "vec op= variable;" to "vec = vec op variable;"
void opOpAssign(string op,T)(T l){
    this  = this.binaryOp!op(l);
}

甚至可以将Vector缩放到其他大小

Vector opBinary(string op)(real l)if(op=="*"||op=="/"){
    mixin("return Vector(x"~op~"l,y"~op~"l;");
}

Vector opBinaryRight(string op)(real l)if(op=="*"){// for 2 * vec
    return this*l;
}

请注意,定义的opBinary限制了可以传递给opOpAssign的内容,但你可以双向操作(以opOpAssign为基础来定义opBinary)。

Johnathan先发了帖子并且解释得更多,所以我把他的标记为答案,但是我也想感谢你的快速回复! - F i L

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接