typeid()面向对象设计备选方案



我有一个使用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()));
    }
}

基本上,我使用templatetypeid(),因为我不喜欢这种依赖于函数名中类型的替代方案:

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()版本似乎正在运行,但我想知道是否有更优雅的解决方案。也许我错过了一些面向对象的设计概念,在这种情况下可能会有所帮助?

提前谢谢。

这非常适合模板专业化:

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

您的问题询问两件事:

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

  2. 还有一个潜在的解决方案,应用"typeid"函数。

更多关于"typeid"的参考:

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

对象(和类)定向是很好的,但是,有时您可能想将其与其他范式混合使用。

"指针"呢?

指针允许将不同的类型视为同一个简单类型。

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

或者更具体地说。"Value"可以是一个元组,其中第一个字段(可能是枚举类型)指示值的真实类型。"Value"的第二个字段是指向实字段的指针或变量。

第一个建议使用"联合"(也称为"变体"),无指针:

#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;
};

这种"模式"我见过好几次了,我称之为"键值类型"集合。

注意:STL的经验不多,你确定"std::map"吗,这是正确的收藏品吗?

只有我的2美分。

可能不是您想要的,因为这是一种不同的方法,但您可以使用变体映射。您可以定义一个boost::变量来只保存string、int或float。

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

最新更新