7

テンプレート化されたいくつかのポリシーを使用するクラスがあります。次の例で呼び出さDishれます。Dishこれらのesの多くを (単純な基本クラスへのポインターを使用して) に格納vectorしていますが、それらを抽出して使用したいと考えています。しかし、私はそれらの正確なタイプを知りません。

コードは次のとおりです。少し長いですが、とてもシンプルです。

#include <iostream>
#include <vector>

struct DishBase {
  int id;
  DishBase(int i) : id(i) {}
};

std::ostream& operator<<(std::ostream& out, const DishBase& d) {
  out << d.id;
  return out;
}

// Policy-based class:
template<class Appetizer, class Main, class Dessert>
class Dish : public DishBase {
  Appetizer appetizer_;
  Main main_;
  Dessert dessert_;
public:
  Dish(int id) : DishBase(id) {}
  const Appetizer& get_appetizer() { return appetizer_; }
  const Main& get_main() { return main_; }
  const Dessert& get_dessert() { return dessert_; }
};

struct Storage {
  typedef DishBase* value_type;
  typedef std::vector<value_type> Container;
  typedef Container::const_iterator const_iterator;
  Container container;
  Storage() {
    container.push_back(new Dish<int,double,float>(0));
    container.push_back(new Dish<double,int,double>(1));
    container.push_back(new Dish<int,int,int>(2));
  }
  ~Storage() {
    // delete objects
  }
  const_iterator begin() { return container.begin(); }
  const_iterator end() { return container.end(); }  
};

int main() {
  Storage s;
  for(Storage::const_iterator it = s.begin(); it != s.end(); ++it){
    std::cout << **it << std::endl;
    std::cout << "Dessert: " << *it->get_dessert() << std::endl; // ??
  }
  return 0;
}

トリッキーな部分は、main()関数にあります。

    std::cout << "Dessert: " << *it->get_dessert() << std::endl; // ??

どうすればデザートにアクセスできますか? ストレージから取得しているオブジェクトの完全な型は言うまでもなく、デザートの型 (テンプレート化されている) もわかりません。

これは単なるおもちゃの例ですが、私のコードはこれに縮小されると思います。これらのクラスを渡したいだけDishで、コードのさまざまな部分がさまざまな部分にアクセスします (例では、前菜、メイン ディッシュ、またはデザート)。

4

3 に答える 3

3

あなたが持っているのは、まさにポリシーベースの設計 IMO ではありません... もしそうなら、クラスは実際にポリシーを実装 (つまり拡張) する必要があります。

さて、質問/例に戻ります。コンテナに「DishBase*」を保存します。右?その時点から、コレクション内のオブジェクトの実際の型に関するコンパイル時の情報が失われます。ですから、あなたがやろうとしていることはおそらく不可能です。

あなたができることは、実際のポリシーベースの設計を使用することです。

template<class Appetizer, class Main, class Dessert>
class Dish : public DishBase, Appetizer, Main, Dessert {
}

次に、単に dynamic_cast を使用して、実行時にオブジェクトを具体的な前菜/デザート/メインに変換できることを確認できます。

しかし、あなたの説明から、実際には抽象基本クラスが必要であるという印象を受けます(つまり、抽象基本クラスは、ポリシーではなく、あなたにとって意味のある設計である可能性があります)。

于 2010-03-25T13:59:02.427 に答える
0

私の理解では、ポリシーベースのテンプレート クラスはあまりコンテナーに適していません。私は、この種のことに対しては、昔ながらのポリモーフィズムを選択しています。私は解決策に興味があります。

編集: Alexandrescu の「Modern C++ Desing」の本全体で stl コンテナーの使用法が見つからないのは、おそらく偶然ではありません。

EDIT2: ポリモーフィズムとジェネリシティ間の摩擦の詳細については、 http://www.artima.com/cppsource/type_erasure.html を参照してください。あなたのコンテナはおそらくboost::anyオブジェクトでできていますか?

于 2010-03-16T21:10:27.777 に答える
0

クエリを実行するには、適切なメンバー関数が必要です (この場合、具体的な Dessert 型のオーバーロード)。ポリシーは、検出方法を公開する必要があります。以下に短い例を示します。

#include <iostream>
using namespace std;

struct TA { virtual string foo() { return "TA::foo\n"; } };
struct DTA  : TA { virtual string foo() { return "DTA::foo\n"; } };

template <class T>
struct C {
    T t;
};

template <class T>
ostream& operator <<(ostream& o, C<T> c) {
    o << c.t.foo();
    return o;
}

int main(int argc, char* argv[]) 
{
    C<DTA> c;
    cout << c;
}
于 2010-03-06T23:45:28.417 に答える