0

リストのようなものを作成しようとしています。ただし、リストのインスタンスが異なればエントリの数も異なる場合があり、エントリのタイプはユーザーの入力に基づきます。たとえば、ユーザーは、リスト内の各エントリの構造に int id、std::string 名、double metricA、および long metricB を含めたいと述べています。この入力に基づいて、以下が作成されます。

struct some_struct {
    int id;
    std::string name;
    double metricA;
    long metricB;
}

list<some_struct> some_list;

ユーザー入力は、ファイルから読み取ったり、画面に入力したりできます。さらに、some_struct 内の可変数のエントリです。つまり、上記のエントリがある場合もあれば、2 つだけある場合もあれば、まったく異なるエントリが 10 ある場合もあります。このような構造体を作成する方法はありますか?

さらに、some_struct の各メンバーに比較演算子を適用できることが必須です。boost::any を使用してデータを保存することもできますが、比較演算子で問題が発生し、理想よりも多くのオーバーヘッドが発生します。

4

3 に答える 3

4

C++ は厳密に型指定された言語です。つまり、データ構造の型を宣言する必要があります。structそのためには、任意の数またはタイプのメンバーで を宣言することはできません。事前に知っておく必要があります。

もちろん、C++ でこのような問題に対処する方法はいくつかあります。いくつか例を挙げると:

  • マップ (std::mapまたはstd::unordered_map) を使用して、構造の代わりに「テーブル」を作成します。文字列を文字列にマッピングします。つまり、名前を値の文字列表現にマッピングし、思い通りに解釈します。
  • のようなあらかじめ用意されたバリアント タイプを使用しboost::anyます。
  • ポリモーフィズムを使用する- ベースへのポインターをリストに格納し、値に対して仮想メカニズム ディスパッチ操作を呼び出します。
  • 入力言語の型システムを作成します。次に、タイプごとの値のテーブルを用意し、リストから適切なテーブルをポイントします。

おそらく C++ プログラマーの数と同じくらい多くの方法があります。

于 2012-05-12T19:33:13.723 に答える
2

さまざまなメンバーを持つデータ構造の問題を解決するには多くの方法があり、どれが最適かは、それがどのように使用されるかによって大きく異なります。

最も明白なのは、継承を使用することです。基本クラスからすべての可能性を導き出します。

struct base_struct { 
    int id;
    std::string name;
};

list<base_struct*> some_list;

struct some_struct : public base_struct {
    double metricA;
};


struct some_other_struct : public base_struct {
    int metricB;
};

base_struct *s1 = new some_struct;
s1->id = 1;
// etc

base_struct *s2 = new some__other_struct;
s2->id = 2;
// etc

some_list.push_back(s1);
some_list.push_back(s2);

注意が必要な点は、要素を元に戻すときに、大文字と小文字を適切に区別する必要があることです。 dynamic_castタイプセーフな方法でこれを行うことができます:

some_struct* ss = dynamic_cast<some_struct*>(some_list.front());

次を使用して、キャストする前に名前を照会できますtype_info

typeid(*some_list.front()).name();

これらはどちらも RTTI でビルドする必要があることに注意してください。通常は問題ありませんが、RTTI にはパフォーマンス コストがかかり、特にテンプレートが広範囲に使用されている場合はメモリ フットプリントが肥大化する可能性があるため、常にそうとは限りません。

以前のプロジェクトでは、 boost anyを使用して同様の処理を行いました。の利点anyは、互いに派生していない型を混在させることができることです。振り返ってみると、型チェックがそれまで延期されているため、コードが実行時に失敗する可能性が少し高くなったため、もう一度やり直すかどうかはわかりません。(これはdynamic_castアプローチにも当てはまります。

古き良き C の時代には、この同じ問題を次のように解決しましたunion

struct base_struct {
    int id;
    std::string name;
    union {  // metricA and metricB share memory and only one is ever valid
        double metricA;
        int metricB;
    };
};

繰り返しになりますが、自分で正しいタイプであることを確認する必要があるという問題があります。

STL が登場する前の時代、多くのコンテナ システムは を取得するように記述されていたためvoid*、ユーザーはいつキャストするかを知る必要がありました。理論的には、そうすることができlist<void*>ますが、型を照会する方法はありません。

編集:絶対にメソッドを使用しないでくださいvoid*

于 2012-05-12T19:37:10.340 に答える
0

boost::variant を含むリストを使用することになりました。パフォーマンスは、boost::any を使用するよりもはるかに優れていました。次のようになりました。

#include <boost/variant/variant.hpp>
#include <list>

typedef boost::variant< short, int, long, long long, double, string > flex; 
typedef pair<string, flex> flex_pair;
typedef list< flex_pair > row_entry;

list< row_entry > all_records;
于 2012-05-13T22:35:41.073 に答える