2

私が今何をしているのかについて、もう少し具体的に説明しましょう。さまざまなアルゴリズムのインターフェイスを定義する抽象オプティマイザー クラスがあります。Request と呼ばれるこのデータ構造の不明な量を生成および消費することで機能するため、それらのベクトルを使用できるようにします。

class Request {
public:
    vector<double> x;
    double y;
    int id;
    // [...]
}

class Asynch_Optimizer {
public:
    virtual int generate_requests( vector<Request> & work ) = 0;
    virtual int assimilate_results( const vector<Request> & result ) = 0;
protected:
    virtual void convergence_test( const vector<Request> & population );
    // [...]
}

Particle_Swarm_Optimizer は、リクエストでいくつかの追加フィールドを使用できることがわかりました。(ここで私の誤謬の匂いがします。追加フィールドは内部でのみ使用されます。リクエスト処理機構には意味がありません。すべてをうまく結合させるために、Particle にサブクラス化しました)

class Particle : public Request {
public:
    vector<double> v;
    vector<double> x_min;
    double min_value;
    // [...]
}

ここで、Particle_Swarm_Optimizer のスーパークラスに実装された一般的な収束テスト メソッドを呼び出したいと思います。ここで、データはパーティクルのベクトルにあります。新しいベクターを構築して各要素を個別にコピーキャストするよりも、 Request のベクターに変換する効率的な方法はありますか?

void opti::Particle_Swarm_Optimizer::convergence_test( const vector<Particle> & population )
{
    //TODO remove slow hack 
    vector<Request> cast_up;
    for (size_t i = 0; i < population.size(); i++) {
        cast_up.push_back( population[i] );
    }
    Asynch_Optimizer::convergence_test( cast_up );
}

この例のデータを構造化するためのより良い方法があると思います。コンテナのテンプレートタイプをアップキャストする方法が存在するかどうか、まだ興味がありますか?

4

3 に答える 3

2

コンテナ内でポインタを使用してもできません。そして、そうしない正当な理由があります。

が のサブタイプであっても、がのSubClassサブタイプでBaseClassあるとは限りません。これが当てはまらない理由は次のとおりです (ベクターだけでなく、あらゆる種類のコンテナーの場合)。vector<SubClass*>vector<BaseClass*>

が のサブクラスvector<SubClass*> として扱われ、から派生しvector<BaseClass*>た 2 番目のクラスがあるとします。このコードを検討してくださいOtherSubClassBaseClass

// This looks logical and is type-safe.
void InsertElement(vector<BaseClass*>& container, BaseClass* element) {
   container.push_back(element);
}

int main() {
  vector<SubClass*> subclass_container;

  // Ok, fine, inserting a SubClass pointer into a vector of
  // SubClass pointers.
  SubClass subclass_obj;
  InsertElement(subclass_container, &subclass_obj);

  // But what about this? Now we're able to insert an 
  // OtherSubClass pointer into that same container!
  OtherSubClass othersubclass_obj;
  InsertElement(subclass_container, &othersubclass_obj);

  // Suddenly, we have a SubClass* that actually points at an
  // OtherSubClass object, when these two are siblings!
  SubClass* subclass_ptr = subclass_container[1];
}

vector<SubClass*>したがって、 のサブクラスとして扱われるべきアイデアを採用した場合、最終的にvector<BaseClass*>は、明らかにタイプ セーフである 2 ビットのコードになります。コンパイラ。

于 2012-12-01T18:51:45.437 に答える
0

現在とほぼ同じように維持したい場合、つまり実行時のポリモーフィズムが必要な場合は、 の概念がany_iterator頭に浮かびます。

基礎となるコンテナと基礎となる型の両方から抽象化する、特別なポリモーフィック イテレータを定義できます。アイデアを得るための小さなスニペットを次に示します (適切な反復子と見なすためのいくつかのメソッドが欠落していますが、残りを自分で実装するのは難しくありません)。

template<class T>
class any_input_iterator : public std::iterator< std::input_iterator_tag,T> {
public:
    any_input_iterator() {}
    any_input_iterator(const any_input_iterator & other) : piter(other.piter->clone()) {}

    template<class Iter>
    any_input_iterator(Iter iter) : piter( new iterator_impl<Iter>(iter)) {}

    T& operator*() {return piter->reference();}

    bool operator==(const any_input_iterator & other) const {
        if ( typeid(*piter) != typeid(* other.piter) ) return false;
        return piter->equal(*other.piter);
    }
    any_input_iterator& operator++() {piter->advance(); return *this;}

private:
    struct iterator_base {
       iterator_base() {}
       virtual ~iterator_base() {}
       virtual void advance() = 0;
       virtual T& reference() = 0;
       virtual iterator_base* clone() = 0;
       virtual bool equal(const iterator_base & other) const = 0;
    };

   template<class InputIterator> struct iterator_impl  : public iterator_base{
       iterator_impl(InputIterator t) : m_iter(t) {}
       virtual void advance() { ++m_iter;}
       virtual T& reference() { return *m_iter;} //assuming this is implicitly castable to T&
       virtual iterator_base* clone() {return new iterator_impl(m_iter);}
       virtual bool equal(const iterator_base & other) const {
        return m_iter ==  dynamic_cast<const iterator_impl&>(other).m_iter;
       }

       InputIterator m_iter;
   };

   std::unique_ptr<iterator_base> piter;
};

アルゴリズムは、コンパイル時に動作する正確な型を知ることができないため、標準の反復子はほとんど役に立ちません。この種のプロキシ イテレータの観点からアルゴリズムを記述すると、問題が解決します。

さらに、私の意見では、イテレータのペアではなくコンテナの観点からアルゴリズムを記述するのは悪い考えです。イテレータのペアに関してコードをリファクタリングしますが、それでもベクトルに固執したい場合は、 を利用してクラスany_iteratorを作成できます。any_vector_reference

これらはすべて、同じタイプのシーケンスがある場合にのみ機能します (そうでない場合は、ポインターのベクトルを操作する必要があります)。

于 2012-12-01T19:33:11.617 に答える
0

1 つの解決策は、オプティマイザーをクラス テンプレートとして定義し、それを使用std::enable_if して型Requestまたはその派生クラスを (未テスト) として動作させることです。

template
<
  typename R, //Request or its derived classes
  typename A = typename std::enable_if
                        <
                           std::is_same<Request, R>::value ||
                           std::is_base_of<Request, R>::value 
                        >::type
>
class Asynch_Optimizer {
public:
    virtual int generate_requests( vector<R> & work ) = 0;
    virtual int assimilate_results( const vector<R> & result ) = 0;
protected:
    virtual void convergence_test( const vector<R> & population );
}
于 2012-12-01T18:57:16.307 に答える