2009-02-20 20 views
13
私は RowColumnクラスを宣言しようとしていますが、 Rowはテンプレート Columnを指す値を持つプライベート std::mapを持っています。

テンプレートクラス値のC++ std :: map

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

基本的には、Rowクラスは、Field(またはColumn)のどの種類を使用したいか、つまり1列目のField<int>か、しかし、Row::column宣言の正しい構文や、std::mapがこの意味で制限されていて、何か他のものを使用しているはずです。

私はあなたの提案を賛美し、それらの前にあなたに感謝します。

+0

何が問題なのですか? –

+1

あなたのコードをhtmlに変換する必要はありません。ちょうどそれを4文字の字下げで置きます。 –

+0

to Dave:私の質問です:Fieldはテンプレート化されているので、どのように値が「あらゆる種類のフィールド」であることをstd :: mapに "伝える"ことができますか? to litb:お寄せいただきありがとうございます! :-) – jbatista

答えて

22

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; 
}; 

コード内にその生ポインタの代わりにスマートポインタを使用することを検討してください。とにかく、問題は型情報が失われていることです - Field<double>またはField<int>を指しているかどうかはもはや知られておらず、テンプレートで設定されたベースに何らかの種類のフラグを保持することによってしか検出できませんまたはRTTIを使用して質問することにより、RTTIを要求します。

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

しかし、それは醜いです。特にあなたが望むのは価値の意味であるからです。私はあなたの行をコピーすることができるようにすると、それはその中のすべてのフィールドをコピーします。また、RTTIを使用して派生型にハックすることなく、ダブルが格納されているときに倍精度浮動小数点型を取得したい場合があります。

これを行う1つの方法は、識別されたユニオンを使用することです。これは、基本的には、任意の型の共用体であり、さらに、そのフィールドに現在格納されている値(たとえば、double型、int型など)を格納する型フラグです。例:

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はすべてあなたのために働きます。訪問を使用して、適切なオーバーロードを使用してFunctorを呼び出すことができます。それを見てmanual

1
  1. ここでエラーが発生しました。フィールドのメンバを "値"にする必要があります(1つはおそらく "タイプ"です)。
  2. 生ポインタをマップの値に保持しないでください。 boost::shared_ptrを使用してください。
  3. また、すでに使用している可能性のあるDB /テーブル処理コードがたくさんあるようなクラスを作成するのは正当な理由があります。したがって、該当する場合は、既存のものを使用し、独自のテーブル処理コードを記述しないことを検討してください。

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

+0

1.申し訳ありませんが、私は意味しました: T avalue; データ型 atype; 2.私はBoostライブラリに精通していません(あなたが話していると思いますが)。 3.私が調べることができる1つまたは2つの提案を指摘してください。 – jbatista

0

Row< int, float, int>は本当に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(Modern C++ Design, by Andrei Alexandrescu参照)によって開拓されましたが、Boostはより現代的であり、よりよくサポートされています。

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

関連する問題