1

私は (私のより知識のある同僚も) 解決方法 (回避策) を知っている問題に出くわしました。最終的に問題になるのは、仮想テンプレート関数を作成できないことです。私はネットを徹底的に検索し、それに対処するいくつかの方法を見つけましたが、私の場合はどれも当てはまらないようです.

この状況を簡単に説明する方法はわかりませんが、最善を尽くし、それが理にかなっていることを願っています.

問題は、2 つの曲線を処理することです。それぞれの曲線は、同じまたは異なる曲線タイプの 1 つまたは複数のセグメントで構成されています。そこで、相互作用する曲線のテンプレート クラスを使用して、曲線セグメントのインターフェイスを作成することから始めました (たとえば、関数は 2 つの異なる曲線セグメント間の交差と同じタイプです)。

template<class curve> class curve_segment { // some methods here }

ユーザーは、いくつかのタイプの曲線と、相互作用する曲線に応じて適切な関数を実装できます。たとえば、circleandlineでは、両方が両方と対話できます。

class line :  public curve_segment<line>, public curve_segment<circle> { //... }
class circle :  public curve_segment<line>, public curve_segment<circle> { //... }

それに続いて、cell2 つの曲線セグメントに依存する class と、cell_baseそれをカプセル化する基本クラスがあります。

template<class curve1, class curve2> class cell : public cell_base { 
  cell_base* up; cell_base* down;

  curve_segment<curve1>* segment_x;
  curve_segment<curve2>* segment_y;

  // some methods that depend on both curves
}

最後に、そのようなセルの 2D グリッド m*n があり、2 つの曲線はcurve_segmentsおそらく異なるタイプの m と n で構成され、各セルの 2 つのポインターによって一緒に保持されます。

新しいcurve_segmentが2つの曲線の1つに追加されると、問題が発生し始めます。明らかな解決策は、追加することです

template<class curve> virtual void add_curve_x(curve_segment<curve> seg) =0;

cell_base実装がcell他の曲線の適切なセグメントを抽出し、それに新しいセルを追加できるクラスに。たとえば、curveabwhereaがグリッドの x 軸を表し、別の曲線セグメントを curve に追加する場合a、グリッドの右側のほとんどのセルを見つけ、そのような各セルの y 軸で曲線を抽出できます。 、そしてそれと新しく提供されたセグメントから新しいセルが作成され、それが右に追加されます。

作成時に新しく追加されたセグメントのタイプを知る必要があるため、タイプの消去は機能しませんcell(両方のセグメントのタイプをテンプレート パラメーターとしてcellクラスに提供する必要があります)。

テンプレートをcell_baseクラスに移動することも機能しません。これは、各cell割り当て時に next の型を知る必要があることを意味するためcurve_segmentです。

これを回避する方法はありますか?

editadd_curve_x : 提案されているように、メソッドを追加します:

template<class curve1, class curve2>
template<class curve> 
cell<curve1, curve>* cell<curve1, curve2>::add_curve_x(curve_segment<curve1>* seg) {
  return new cell<curve1, curve>(seg, (curve_segment<curve>*)(this->segment_y));
}

この場合、実装segする必要があるタイプである必要があります。も実装する必要があります。curvecurve_segment<curve1>segment_ycurve_segment<curve>

編集2:キャストが存在する理由の説明

写真

太字でない長方形の場合を考えてみましょう。そのような状況では、a2 つのセグメントを持つカーブbと 3 つのセグメントを持つカーブの 2 つのカーブがあります。classlineは とcurve_segment<line>同様に実装curve_segment<circle>する必要があり、 circle も両方を実装する必要があります。次に、別のベジエ曲線セグメントを curve に追加しましょうa。クラスbezierは と を実装する必要がcurve_segment<line>ありcurve_segment<circle>linecircleは を実装する必要がありますcurve_segment<bezier>

太字の 3 つの中間を作成する方法を見てみましょうcells。私たちは電話をかけます

add_curve_x<bezier>(new bezier(...));

型のセル オブジェクトcell<circle, circle>

引数segは新しいbezierオブジェクト ( にキャストできるcurve_segment<circle>) になり、それがcurveタイプであり、segment_yにキャストする必要がありますcurve_segment<bezier>。これは、新しく作成されたセルで相互作用している曲線のタイプであるためです。

4

1 に答える 1

0

追加curve_segment_base:

class curve_segment_base {
   // for double dispatching here:
  virtual cell_base* add_curve_x(cell_base* cell) = 0;
};

template<class curve> 
class curve_segment : public virtual curve_segment_base { 
     // some specific methods here 
     // for double dispatching here:
     virtual cell_base* add_curve_x(cell_base* cell)
     {
         // this has to be moved to cpp file due to dependency from cell_base
         return cell->add_curve_x(this); // now the correct method from cell is called
     }
};

したがって、このメソッドを仮想として cell_base に追加できます

class cell_base {
   virtual cell_base* add_curve_x(curve_segment_base* seg) = 0;

   // methods necessary for double dispatching here:
   virtual cell_base* add_curve_x(curve_segment<line>* seg) = 0;
   virtual cell_base* add_curve_x(curve_segment<circle>* seg) = 0;
   ...
};

したがって、ここで二重ディスパッチを使用すると、メソッドは次のようになります。

template<class curve1, class curve2>
virtual cell_base* cell<curve1, curve2>::add_curve_x(curve_segment_base* seg) {
  return seg->add_curve_x(this);
}

そして、すべてのセグメントに対して実際の実装方法をすべて実装する必要があります。

template<class curve1, class curve2>
virtual cell_base* cell<curve1, curve2>::add_curve_x(curve_segment<line>* seg) {
  return new cell<curve1, line>(...);
}
template<class curve1, class curve2>
virtual cell_base* cell<curve1, curve2>::add_curve_x(curve_segment<circle>* seg) {
  return new cell<curve1, circle>(...);
}
于 2012-10-18T15:01:11.737 に答える