【问题标题】:Elegant operator overloading in DD 中优雅的运算符重载
【发布时间】:2011-12-11 05:32:32
【问题描述】:

有一段时间我对 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 之后不会继续关注ifs。你必须再次重复static

标签: operator-overloading d dmd gdc


【解决方案1】:

几乎所有 D 中的重载运算符都是模板根据定义。请注意,void opOpAssign(string op)(Vector vector) 有一个模板参数,它是一个字符串。因此,不,您不能将其作为非模板函数重载。现在,您不需要第二个模板来执行此操作(因此,如果询问是否需要模板,您的意思是辅助模板,那么答案是否定的),但是重载的运算符函数已经是一个模板。

执行您在此处尝试执行的操作的规范方法是使用字符串混合:

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

【讨论】:

    【解决方案2】:

    这意味着要与 mixins 结合使用

    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 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;
    }
    

    请注意,定义的opBinarys 限制了可以传递给opOpAssign 的内容,但您可以双向使用(根据opOpAssign 定义opBinary

    【讨论】:

    • Johnathan 先发帖并解释了更多,所以我将他标记为答案,但我也要感谢您如此迅速的回复!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-27
    • 2012-10-08
    • 2020-12-28
    • 1970-01-01
    相关资源
    最近更新 更多