23

特定のデータ ソースに関するメタデータを格納するクラスを作成中です。メタデータは、XML の構造と非常によく似たツリー構造になっています。メタデータ値は、整数、10 進数、または文字列値にすることができます。

このような状況で C++ にバリアント データを保存する良い方法があるかどうか、興味があります。バリアントで標準ライブラリを使用したいので、利用可能な COM、Ole、および SQL VARIANT 型を避けています。

私の現在のソリューションは次のようになります。

enum MetaValueType
{
    MetaChar,
    MetaString,
    MetaShort,
    MetaInt,
    MetaFloat,
    MetaDouble
};

union MetaUnion
{
    char cValue;
    short sValue;
    int iValue;
    float fValue;
    double dValue;
};

class MetaValue
{
...
private:
    MetaValueType ValueType;
    std::string StringValue;
    MetaUnion VariantValue;
};

MetaValue クラスには、現在格納されているバリアント値を取得するためのさまざまな Get 関数がありますが、値のすべてのクエリを if/else if ステートメントの大きなブロックにして、探している値を見つけ出します。

また、値を文字列のみとして保存し、変換を実行してさまざまなバリアント型を取得することも検討しましたが、これを見る限り、内部文字列の解析とエラー処理が大量に発生し、きれいではありません。浮動小数点値の精度とデータ損失の問題の大きな古い缶をアップしますが、それでも上記の if/else if の問題を排除しません。

標準ライブラリを使用して C++ バリアント データ型に使用するのにクリーンなものを実装または見た人はいますか?

4

5 に答える 5

33

C++17 の時点では、std::variant.

まだ使用できない場合は、Boost.Variantが必要になる場合があります。ポリモーフィズムをモデル化するための、類似しているが異なるタイプがstd::any(および、C++17 より前のBoost.Any ) によって提供されます。

追加のポインタとして、「<a href="https://stackoverflow.com/q/5450159/1968">type erasure」を探すことができます。

于 2008-10-16T15:12:03.787 に答える
13

Konrad の回答 (既存の標準化されたソリューションを使用) は、バグが発生しやすい独自のバージョンを作成するよりも確かに望ましいものですが、ブースト バリアントには、特にコピーの構築とメモリにおいて、いくつかのオーバーヘッドがあります。

一般的なカスタマイズされたアプローチは、次の変更された Factory パターンです。

  1. オブジェクト型を (列挙型として) カプセル化するか、'typeid' を使用する (推奨) ジェネリック オブジェクトの Base インターフェイスを作成します。
  2. 次に、テンプレートDerivedクラスを使用してインターフェイスを実装します。
  3. create署名付きのテンプレート化された関数でファクトリ クラスを作成します。

template <typename _T> Base * Factory::create ();

これにより、内部的Derived<_T>にヒープ上にオブジェクトが作成され、動的キャスト ポインターが返されます。実装するクラスごとにこれを特化します。

最後に、このポインターを含み、テンプレートの get および set 関数を定義するVariantラッパーを定義します。、、代入演算子、等価演算子などのBase *ユーティリティ関数は、ここで適切に実装できます。getType()isEmpty()

ユーティリティ関数とファクトリの実装に応じて、サポートされるクラスは代入やコピー構築などのいくつかの基本的な機能をサポートする必要があります。

于 2009-11-16T03:29:09.463 に答える
9

システム上の double のサイズの void* と、使用している型の列挙型を持つ、より C っぽいソリューションに進むこともできます。それはかなりきれいですが、システムの生のバイトに完全に慣れている人にとっては間違いなく解決策です.

于 2008-10-16T15:30:15.513 に答える
4

質問には長い間回答がありましたが、記録として、Qt ライブラリのQVariantもこれを行うことに言及したいと思います。

C++ はユニオンにデフォルト以外のコンストラクターまたはデストラクタを持つ型を含めることを禁止しているため、ほとんどの興味深い Qt クラスはユニオンで使用できません。QVariant がないと、これは QObject::property() やデータベース作業などで問題になります。

QVariant オブジェクトは、一度に 1 つの type() の 1 つの値を保持します。(一部の type() は、文字列リストなど、多値です。) バリアントが保持する型 T を調べ、convert() を使用して別の型に変換し、toT のいずれかを使用してその値を取得できます。 () 関数 (例: toSize()) を呼び出し、canConvert() を使用して型を特定の型に変換できるかどうかを確認します。

于 2015-04-15T06:44:09.370 に答える