18

テンプレート化されたを指す値を持つプライベートを持つことで、RowColumnクラスを宣言しようとしています。このようなもの:Rowstd::mapColumn

template <typename T> class DataType {
  private:
    T type;
};
template <typename T> class Field {
  private:
    T value;
    DataType<T> type;
};
class Row {
  private:
    std::map<unsigned long,Field*> column;
}; 

まあ、原則として、クラスは使用したい種類(または)をRow知る必要はないと思います。つまり、1列目か2列目かはわかりません。しかし、正しい構文が何であるかはわかりません。宣言のために、またはこの意味で制限されていて、私が何か他のものを使用する必要がある場合。FieldColumnField<int>Field<double>Row::columnstd::map

よろしくお願いします。よろしくお願いします。

4

3 に答える 3

29

Field単独では型ではなく、やなどの型のファミリーを生成できるテンプレートField<int>ですField<double>。これらのフィールドはすべて、一方が他方から派生しているなどの関係はありません。したがって、これらすべての生成されたタイプの間に何らかの関係を確立する必要があります。1つの方法は、一般的な非テンプレート基本クラスを使用することです。

class FieldBase { };

template <typename T>
class Field : public FieldBase {
  private:
    T value;
    DataType<T> type;
};
class Row {
  private:
    std::map<unsigned long,FieldBase*> column;
}; 

そして、コードでその生のポインターの代わりにスマートポインターを使用することを検討してください。とにかく、今問題はタイプ情報が失われることです-あなたがaを指すかaを指すかはField<double>もうField<int>わからず、テンプレート化された派生クラスによって設定されたベースにある種のタイプフラグを保持することによってのみ検出できます-またはを使用してRTTIに質問する

dynamic_cast<Field<int>*>(field) != 0

しかし、それは醜いです。特にあなたが望むものには価値セマンティックがあるからです。つまり、行をコピーできるようにすると、その中のすべてのフィールドがコピーされます。また、doubleが格納されている場合は、最初にRTTIを使用して派生型にハックすることなく、doubleを取得する必要があります。

これを行う1つの方法は、識別された共用体を使用することです。これは基本的に、いくつかの任意の型の和集合であり、さらに、そのフィールドに現在格納されている値(たとえば、double、int、...)を格納するtype-flagです。例えば:

template <typename T>
class Field {
  private:
    T value;
    DataType<T> type;
};
class Row {
  private:
    std::map<unsigned long, 
             boost::variant< Field<int>, Field<double> > > 
      column;
};

boost::variantがすべての作業を行います。訪問を使用して、適切なオーバーロードを使用してファンクターを呼び出すことができます。そのマニュアルを見てください

于 2009-02-20T10:58:24.780 に答える
2
  1. そこでエラーが発生しました。フィールドのメンバーを「評価」する必要があります(おそらく「タイプ」である必要があります)。
  2. マップの値に生のポインタを保持しないでください。boost::shared_ptrを使用します。
  3. また、おそらく使用できるDB /テーブル処理コードがすでにたくさんあるようなクラスを作成するのには、十分な理由があるはずです。したがって、該当する場合は、既存のものを使用し、独自のテーブル処理コードを記述しないことを検討してください。

さて、あなたの質問に答えるために:)、Field <>クラスは、すべてのデータ型で共有される共通の基本クラスから継承できます。このようにして、列マップなどのコンテナーは、テンプレートクラスのインスタンス化された派生オブジェクトへのポインターを保持できます(共有ポインターを作成します)。

于 2009-02-20T10:49:09.340 に答える
0

ARow< int, float, int>は a とはまったく異なりRow<int, std::string>ます。明らかにRow<int,float,int>.field<0>Field<int> しばらくRow<int,float,int>.field<1>する必要がありField<float>ます。そして Row<int,float,int>.field<3>コンパイルエラーです。

これを行う最も簡単な方法は、Boost を使用することです。多くのインテリジェンスは Loki によって開発されました ( Andrei Alexandrescu によるModern C++ Designを参照) が、Boostはより最新であり、より適切にサポートされています。

通常、フィールドを反復処理することはありません。各フィールドには独自の型があります。しかし、あなたがそうするなら、あなたは確かにFieldBase. そのようなインターフェースが必要な場合は、フィールドを として内部的に保存することもおそらく価値がありますboost::array<FieldBase, N>(つまりRow<int,float,int>、 を持っていますboost::array<FieldBase, 3>)。dynamic_castただし、その必要はありませんFieldBase*。これは実行時テストであり、コンパイル時Tにそれぞれの正確な値を常に知っています。Field<T>

于 2009-02-20T13:24:30.497 に答える