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

これは、1つのメソッドですべての+ =、-=、*=などの演算子をオーバーロードするので機能する場合は美しいコードになります。ただし、ご覧のとおり、そのままでは機能しません。テンプレートを使用してソリューションを作成しました(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);
    }
}

これは問題ありません。すべてを「社内」に保管したいのは私だけです。テンプレートを使用せずにこれを機能させる方法はありますか?パフォーマンスの低下はなく、これを行う必要がある状況でモジュールをインポートするのは難しくないので、私はここで気難しいことを知っています。内蔵されているのかと思っていて、何かを見落としています。

4

2 に答える 2

22

D でオーバーロードされたほとんどすべての演算子は、定義上テンプレートです。void opOpAssign(string op)(Vector vector)文字列であるテンプレート パラメータがあることに注意してください。したがって、非テンプレート関数としてオーバーロードすることはできません。これを行うために 2 番目のテンプレートは必要ありません (つまり、テンプレートが必要かどうかを尋ねたときにヘルパー テンプレートを意味する場合、答えはいいえです) が、オーバーロードされた演算子関数は既にテンプレートです。

ここでやろうとしていることを行う標準的な方法は、文字列 mixin を使用することです。

void opOpAssign(string op)(Vector vector)
{
    mixin("X" ~ op ~ "=vector.X;");
    mixin("Y" ~ op ~ "=vector.Y;");
}
于 2011-10-19T19:37:46.643 に答える
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 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ますが、両方の方法で行くことができることに注意してください (opBinaryに関して定義しますopOpAssign)

于 2011-10-19T19:34:49.363 に答える