質問
特定のデータソースに関するメタデータを格納するクラスを作成中です。メタデータはツリー構造であり、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 ++バリアントデータ型に使用するクリーナーを実装または表示した人はいますか?
解決
C ++ 17現在、 std: :variant
。
まだ使用できない場合は、 Boost.Variant 。ポリモーフィズムをモデル化するための類似しているが明確なタイプは、 std :: anyによって提供されます。
(およびC ++ 17より前の Boost.Any )。
追加のポインタとして、“ タイプ消去”を探すことができます。
他のヒント
Konradの回答(既存の標準化されたソリューションを使用する)は、バグが発生しやすい独自のバージョンを作成するよりも確かに望ましいのですが、boostバリアントには、特にコピーの構築とメモリのオーバーヘッドがあります。
カスタマイズされた一般的なアプローチは、次の修正されたファクトリパターンです。
- (enumとして)オブジェクトタイプをカプセル化する、または「typeid」(推奨)を使用する汎用オブジェクトのベースインターフェイスを作成します。
- テンプレート
Derived
クラスを使用してインターフェイスを実装します。 - 署名付きのテンプレート化された
create
関数を使用してファクトリクラスを作成します。
template< typename _T>ベース* Factory :: create();
これは、ヒープ上に Derived< _T>
オブジェクトを内部的に作成し、動的キャストポインターを再チューニングします。実装するクラスごとにこれを特化してください。
最後に、この Base *
ポインターを含み、テンプレートのgetおよびset関数を定義する Variant
ラッパーを定義します。ここでは、 getType()
、 isEmpty()
、代入演算子および等値演算子などのユーティリティ関数を適切に実装できます。
ユーティリティ関数とファクトリー実装に応じて、サポートされているクラスは、割り当てやコピー構築などの基本的な機能をサポートする必要があります。
また、システムでdoubleのサイズのvoid *と、使用している型の列挙型を持つ、よりC風のソリューションに進むこともできます。かなりきれいですが、システムの生のバイトに完全に満足している人にとっては間違いなく解決策です。
C ++ 17に std :: variant
が追加されました。これはまさにあなたが探しているものです。
この質問には長い間回答がありましたが、記録のために QVariant もこれを行います。