6

次のように、C++で「スパース」ベクトルクラスを作成しようとしています。

template<typename V, V Default>
class SparseVector {
    ...
}

内部的には、std::map<int, V>V格納されている値のタイプは)で表されます。要素がマップに存在しない場合はDefault、テンプレート引数の値と等しいと見なします。

ただし、添え字演算子のオーバーロードに問題があります[]。このクラスのオブジェクトを、正しく[]機能することを期待するBoost関数に渡すため、演算子をオーバーロードする必要があります。[]

constバージョンは非常に単純です。インデックスがマップにあるかどうかを確認し、ある場合はその値を返すか、そうでない場合はその値を返しますDefault

ただし、非constバージョンでは参照を返す必要があり、そこで問題が発生します。値が読み取られているだけの場合は、マップに何も追加する必要はありません(または追加したくありません)。しかし、それが書かれている場合、私はおそらくマップに新しいエントリを入れる必要があります。問題は、オーバーロードされた値が値の読み取りまたは[]書き込みのどちらであるかを認識しないことです。単に参照を返すだけです。

この問題を解決する方法はありますか?またはおそらくそれを回避するために?

4

3 に答える 3

13

operator[]非常に単純なトリックがあるかもしれませんが、そうでなければ、必ずしもV&ではなく、Vから割り当てられる(そしてVに変換される)ものを返すだけでよいと思います。したがって、オーバーロードされたオブジェクトを返す必要があると思いますoperator=(const V&)。これにより、スパースコンテナにエントリが作成されます。

ただし、Boost関数がそのテンプレートパラメータで何をするかを確認する必要があります。たとえば、Vへのユーザー定義の変換は、同じチェーン内にユーザー定義の変換がこれ以上ないようにするなど、可能な変換チェーンに影響します。

于 2009-09-06T16:41:39.917 に答える
9

const 以外の operator& の実装が参照を返すのではなく、プロキシ オブジェクトを返さないでください。その後、proxy オブジェクトの代入演算子を実装して、operator[] への読み取りアクセスと書き込みアクセスを区別できます。

アイデアを説明するためのコード スケッチを次に示します。このアプローチはきれいではありませんが、これは C++ です。C++ プログラマーは、美人コンテストで競争して時間を無駄にすることはありません (彼らにもチャンスはありません)。;-)

template <typename V, V Default>
ProxyObject SparseVector::operator[]( int i ) {
   // At this point, we don't know whether operator[] was called, so we return
   // a proxy object and defer the decision until later
   return ProxyObject<V, Default>( this, i );
}

template <typename V, V Default>
class ProxyObject {
    ProxyObject( SparseVector<V, Default> *v, int idx );
    ProxyObject<V, Default> &operator=( const V &v ) {
      // If we get here, we know that operator[] was called to perform a write access,
      // so we can insert an item in the vector if needed
    }

    operator V() {
      // If we get here, we know that operator[] was called to perform a read access,
      // so we can simply return the existing object
    }
};
于 2009-09-06T17:43:57.497 に答える
1

このデザインは健全なのだろうか。

参照を返したい場合、それは、クラスのクライアントが呼び出しの結果をoperator[]参照に保存し、後でいつでも読み書きできることを意味します。参照を返さない、および/または特定のインデックスがアドレス指定されるたびに要素を挿入しない場合、どうすればこれを行うことができますか? (また、標準では、その演算子が参照を返すように提供する適切な STL コンテナーが必要であると感じていますがoperator[]、それについてはわかりません。)

operator V&()プロキシにも(エントリを作成してデフォルト値を割り当てる)を与えることでそれを回避できるかもしれませんが、これが別のループホールを開くだけではないかどうかはわかりません。まだ。

std::mapこの問題は、その演算子の非 const バージョンが常に要素を挿入する (そしてバージョンをまったく提供しない) ことを指定することで解決されconstます。

もちろん、これは既製の STL コンテナーではなく、ユーザーが保存できるプレーンな参照を返さないと常に言えますoperator[]。そして多分それは大丈夫です。不思議に思います。

于 2009-09-06T20:06:36.070 に答える