5

3 つの異なるマップを使用する次のクラスがあります。キーは常に文字列ですが、値は文字列、整数、または浮動小数点数の場合があります。

class MyMaps
{

public:

    template<typename T> void addKey(const std::string& key);
    void addValue(const std::string& key, const std::string& value);
    void addValue(const std::string& key, int value);
    void addValue(const std::string& key, float value);

private:

    std::map<std::string, std::string> stringFields;            
    std::map<std::string, int> intFields;                       
    std::map<std::string, float> floatFields;                   
};

関数はaddValue()、関連するマップに新しいペアを追加するだけです。私が取り組んでいるのはaddKey()テンプレート関数です:

/** Add only a key, the related value is a default one and is specified by template parameter T. */

template<typename T>
void MyMaps::addKey(const string& key)
{       
    if (typeid(T) == typeid(string))
    {
        stringFields.insert(pair<string, string>(key, string()));
    }

    else if (typeid(T) == typeid(int))
    {
        intFields.insert(pair<string, int>(key, int()));;
    }

    else if (typeid(T) == typeid(float))
    {
        floatFields.insert(pair<string, float>(key, float()));
    }
}

基本的に、type-within-function-name に依存するこの代替手段が気に入らないためtemplate、 andを使用しています。typeid()

void MyMaps::addStringKey(const string& key) 
{
    stringFields.insert(pair<string, string>(key, string()));
}

void MyMaps::addIntKey(const string& key) 
{
    intFields.insert(pair<string, int>(key, int()));
}

void MyMaps::addFloatKey(const string& key) 
{
    floatFields.insert(pair<string, float>(key, float()));
}

最初のaddKey()バージョンは機能しているようですが、もっと洗練されたソリューションがあるかどうか疑問に思っています。この場合に役立つ可能性のあるオブジェクト指向の設計概念が欠けているのではないでしょうか?

前もって感謝します。

4

3 に答える 3

6

これは、テンプレートの特殊化に最適です。

template<>
void MyMaps::addKey<string>(const string& key)
{       
    stringFields.insert(pair<string, string>(key, string()));
}

template<>
void MyMaps::addKey<int>(const int& key)
{   
    intFields.insert(pair<string, int>(key, int()));;
}

template<>
void MyMaps::addKey<float>(const float& key)
{   
    floatFields.insert(pair<string, float>(key, float()));
}

編集:構文/テンプレートの特殊化に関する詳細については、「テンプレートの特殊化と部分的なテンプレートの特殊化」を参照してください。

または、ブーストがオプションであり、キーが3つのマップすべてで一意であり、それらを格納できるようにするためだけに3つの異なるマップがある場合は、次の使用を検討してboost::variantください。

typedef boost::variant<string, int, float> ValueType;

class MyMap
{

public:
    typedef std::map<std::string, ValueType> MapType;
    template<typename T> void addKey(const std::string& key, T &val)
    {
        ValueType varVal= val;
        allFields.insert(MapType::value_type(key, varVal));
    }

private:

    MapType allFields;                              
};
于 2013-02-14T18:59:03.920 に答える
2

あなたの質問は2つのことを尋ねます:

  1. 本当の問題は、同じコレクション内の値に異なるタイプを使用して、キーと値のマップまたはディクショナリを作成することです。

  2. そして、「typeid」関数を適用する潜在的な解決策。

「typeid」に関するその他の参照:

http://en.cppreference.com/w/cpp/language/typeid

オブジェクト (およびクラス) 指向は優れていますが、他のパラダイムと組み合わせたい場合があります。

「ポインタ」はどうですか?

ポインターを使用すると、異なる型を同じ単純型として扱うことができます。

文字列キーとポインタ値を格納するキー値ディクショナリ コレクションについてはどうでしょうか。ポインタは整数、文字列、またはオブジェクトの場合があります。

またはより具体的に。「値」は、最初のフィールド (おそらく列挙型) が値の実際の型を示すタプルである場合があります。また、「値」の 2 番目のフィールドは、実際のフィールドへのポインターまたはバリアントです。

「ユニオン」(別名「バリアント」)を使用した最初の提案、ポインターなし:

#include <string>
#include <typeinfo>

union ValueUnion
{
   int AsInt,
   float AsFloat,
   std::string& AsStr
};

struct ValueType
{
  std::type_info Id,
  ValueUnion Value 
};

class MyMaps
{
public:
    template<typename T> void addKey(const std::string& key);
    void addValue(const std::string& key, const std::string& value);
    void addValue(const std::string& key, int value);
    void addValue(const std::string& key, float value);
private:

    std::map<std::string, ValueType> Fields;    
};

または、ポインターを使用して:

#include <string>
#include <typeinfo>

struct ValueType
{
  std::type_info Id,
  void* Value 
};

class MyMaps
{
public:
    template<typename T> void addKey(const std::string& key);
    void addValue(const std::string& key, const std::string& value);
    void addValue(const std::string& key, int value);
    void addValue(const std::string& key, float value);
private:
    std::map<std::string, ValueType> Fields;
};

この「パターン」を何度か見たことがありますが、私は「Key-Value-Type」コレクションと呼んでいます。

注: STL の経験はあまりありません。「std::map」は正しいコレクションですか?

ちょうど私の2セント。

于 2014-07-16T16:59:13.663 に答える
0

これは別のアプローチであるため、あなたが望むものではないかもしれませんが、バリアントのマップを使用できます。boost::variantを定義して、string、int、または float のみを保持できます。

eladidan は私を打ち負かし、回答を削除する方法がわかりません。

于 2013-02-14T19:10:28.257 に答える