c++ - 参照 - ムーブコンストラクタ



新しいc++ 0x rvalue参照演算子のオーバーロードを追加する際の冗長コードの削減方法 (3)

私は新しいオペレータのオーバーロードを追加して、C ++ 0x rvalueの参照を利用しています。私はたくさんの冗長コードを生成しているように感じます。

私はクラス、 treeを持っています。それは二重値の代数演算のツリーを保持しています。 使用例の例を次に示します。

tree x = 1.23;
tree y = 8.19;
tree z = (x + y)/67.31 - 3.15*y;
...
std::cout << z; // prints "(1.23 + 8.19)/67.31 - 3.15*8.19"

各バイナリ演算(プラスのような)では、各辺は左辺値tree 、右辺値tree 、またはdouble値のいずれかになります。 これにより、バイナリ操作ごとに8つのオーバーロードが発生します。

// core rvalue overloads for plus:
tree operator +(const tree& a, const tree& b);
tree operator +(const tree& a, tree&&      b);
tree operator +(tree&&      a, const tree& b);
tree operator +(tree&&      a, tree&&      b);

// cast and forward cases:
tree operator +(const tree& a, double      b) { return a + tree(b); }
tree operator +(double      a, const tree& b) { return tree(a) + b; }
tree operator +(tree&&      a, double      b) { return std::move(a) + tree(b); }
tree operator +(double      a, tree&&      b) { return tree(a) + std::move(b); }

// 8 more overloads for minus

// 8 more overloads for multiply

// 8 more overloads for divide

// etc

各バイナリ演算(マイナス、乗算、除算など)のためにも繰り返される必要があります。

ご覧のとおり、私が実際に書く必要のある関数は4つしかありません。 他の4人はキャストしてコアケースに転送することができます。

このコードのサイズを縮小するための提案はありますか?

PS:実際には、クラスは単なるダブルスのツリーより複雑です。 コピーを減らすと、プロジェクトのパフォーマンスが大幅に向上します。 だから、余分なコードがあっても、価値のある過負荷は私には価値がある。 上記の "キャストアンドフォワード"のケースをテンプレートにする方法があるかもしれないという疑いがありますが、私は何も考えるようには思えません。

https://src-bin.com


Answer #1

あなたはメンバー関数としてそれらを定義することになっているので、lvalueまたはrvalueをプライマリユニットとしてオーバーロードする必要はありません(これはとにかく不要です)。つまり、

class Tree {
    Tree operator+ const (const Tree&);
    Tree operator+ const (Tree&&);
};

最初のもののlまたはrの大小が無関係であるためです。 さらに、コンストラクターが利用可能な場合、コンパイラーが自動的に作成します。 treeがdoubleから構築する場合、自動的にここでdoubleを使用することができ、doubleは適切なrvalueになります。 これはちょうど2つの方法です。


Answer #2

ちょっと遅い答え:問題のクラスが移動可能な場合、移動は非常に安価です。可能であれば、すべての引数から移動し、値で引数を渡すことも可能です。

tree operator +(tree      a, tree      b);

treeが移動可能で、実引数としてrvalue refが渡された場合、関数の引数は、可能であればツリーの移動コンストラクタで初期化され、そうでない場合はコピーコンストラクタで初期化されます。 それから、関数は引数を引数として適切な方法で(例えば、内部を動かすなど)何でもできます。

rvalue参照引数を渡したときに、たくさんのオーバーロードのバージョンと比べて余分な動きがありますが、一般的にはそれが良いと思います。

また、IMO、 tree &&引数は一時的なコピーを介して左辺値を受け入れるべきですが、これはコンパイラが現在行っていることではないのであまり役に立ちません。


Answer #3

問題は、const以外のパラメータで操作を定義したことです。 定義した場合

tree operator +(const tree& a, const tree& b);

r値とl値参照の間に違いはないので、あなたも定義する必要はありません

tree operator +(tree&&      a, const tree& b);

さらに、doubleがtree x = 1.23;ようにtree x = 1.23;変換可能ならば、 あなたはどちらも定義する必要はないと思う

tree operator +(double      a, const tree& b){ return tree(a) + b; }

コンパイラがあなたのために作業を行います。

演算子+がツリーパラメータを値で取る場合は、右辺値と左辺値の差を作る必要があります

tree operator +(tree a, tree b);




rvalue-reference