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

基本上,我使用templateandtypeid()因为我不喜欢这种依赖于type-within-function-name 的替代方案:

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

编辑:有关模板专业化的语法/更多信息,请阅读:模板专业化和部分模板专业化

或者更好的是,如果 boost 是一个选项,并且所有 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

您的问题询问了两件事:

  1. 真正的问题是,在同一个集合中为值使用不同类型的键值映射或字典。

  2. 并且,一个潜在的解决方案是应用“typeid”函数。

关于“typeid”的更多参考:

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

面向对象(和类)方向很棒,但有时您可能希望将其与其他范式混合使用。

“指针”呢?

指针允许不同的类型被视为相同的简单类型。

键值字典集合呢,它存储一个字符串键和一个指针值,指针可以是整数、字符串或对象。

或者更具体一点。“Value”可能是一个元组,其中第一个字段(可能是枚举类型)表示值的真实类型。而且,“值”的第二个字段是指向实际字段的指针或变体。

使用“Unions”(又名“variants”)的第一个建议,没有指针:

#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来只保存字符串、整数或浮点数。

eladidan 打败了我,我不知道如何删除答案。

于 2013-02-14T19:10:28.257 回答