1

私は、より効果的な C++ の項目 22 にある Scott Meyers のアドバイスに従おうとしています:「op=スタンドアロンではなく使用を検討してくださいop」。彼は、 のテンプレートを作成してoperator+、実装するすべてのクラスがoperator+=自動的に を取得できるようにすることを提案していoperator+ます。

template<class T>
const T operator+(const T& lhs, const T& rhs)
{ 
    return T(lhs) += rhs; 
}

さて、Effective Modern C++ の項目 25 には、行列の加算の例 (pg. 172) があります。そこでは、右辺値を使用したオーバーロードoperator+が提案されていますlhsrhsおそらく巨大な行列の無用なコピー。だから私はオーバーロードを追加しました:

template<class T>
T operator+(T&& lhs, const T& rhs)
{ 
    return std::move(lhs += rhs);
}

template<class T>
T operator+(T const& lhs, T&& rhs)
{ 
    return std::move(rhs += lhs);
}

template<class T>
T operator+(T&& lhs, T&& rhs)
{ 
    return std::move(lhs += rhs);
}

ここでの問題は、それT&&が普遍的な参照であり、すべてをキャプチャすることになるため、左辺値から移動することになりますが、これは望ましくない動作です。

operator+では、テンプレートを適切に実装するにはどうすればよいでしょうか。

値渡しを使用した部分的な解決策:アイテム 41: "コピー可能なパラメーターの値渡しを検討してください..." も読んだので、Effective Modern C++ から、次のような独自のバージョンを作成しようとしました。

template<class T>
const T operator-(T lhs, T rhs)
{
    return lhs -= rhs;
}

しかし、rhs が右辺値の場合、これは最適化の機会を逃します。この場合、rhs を使用して結果を格納しないからです。したがって、これは部分的な解決策にすぎません。

4

1 に答える 1

3

あなたの問題は、C++03 のアドバイス (ジェネリックを作成するoperator+) と適切な C++11 のアドバイス (右辺値のオーバーロード)を組み合わせようとしていることoperator+にあり、2 つのアドバイスは必ずしも互換性があるとは限りません。

operator+書きたいジェネリックを転送参照で正しく行うのは難しいですが、元のアプローチと同じアプローチに従ってlhs、右辺値の場合は移動する一時的なものを作成できますstd::forward(「ユニバーサル参照」は現在、転送として知られています参照std::forwardであり、それらに対処する最善の方法は通常そうではないという手がかりを与えるはずですstd::move):

template<class T>
    T operator+(T&& lhs, const T& rhs)
    {
        T tmp{ std::forward<T>(lhs) };
        tmp += rhs;
        return tmp;
    }

これは左側の右辺値のみTを受け入れることに注意してください。他のパラメーターは、などの参照型として推定され X&ず、 などのオブジェクト型のみとして推定されるXため、最初のパラメーターは右辺値のみに一致する可能性があるためです。

したがって、左辺が左辺値である場合に別のオーバーロードを追加できます。

template<class T>
    T operator+(const T& lhs, const T& rhs)
    {
        T tmp{lhs};
        tmp += rhs;
        return tmp;
    }

どちらのオーバーロードも右辺値の場合は再利用されないため、これは完全に最適ではない可能性がありますがrhs、上記のコメントで述べたように、rhs += lhs加算が交換可能でない限り正しくありません。交換できると仮定してよろしい場合は、これを改善してrhs、右辺値の場合に再利用することができます (オーバーロードと複雑さを追加することにより)。

operator+個人的には、の観点から定義されたジェネリックは演習として興味深いと思いますoperator+=が、実際にはあまり実用的ではなく、特にムーブ セマンティクスを考慮する場合はそうです。型のカスタムoperator+を書くこと (More Effective C++ の p172 にあるようなもの) はそれほど多くの作業ではなく参照の転送に対処する必要はありません。安全に行うrhs += lhsかどうか。

于 2015-07-24T15:54:29.033 に答える