typeid()面向对象的设计替代方案

时间:2013-02-14 18:51:01

标签: c++ oop collections 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(),因为我不喜欢依赖于 type-in​​-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()版本似乎正在运行,但我想知道是否有更优雅的解决方案。也许我错过了一些面向对象的设计概念,在这种情况下可能会有所帮助?

提前致谢。

3 个答案:

答案 0 :(得分: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()));
}

编辑:有关模板专业化的语法/更多信息,请阅读:Template Specialization and Partial Template Specialization

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

你的问题询问了两件事:

  1. 真正的问题是,在同一个集合中为值使用不同类型制作关键值Map或Dictionary。

  2. 并且,一个潜在的解决方案,应用&#34; typeid&#34;功能

  3. 有关&#34; typeid&#34;的更多参考:

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

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

    怎么样&#34;指针&#34; ?

    指针允许使用不同的类型,将其视为相同的简单类型。

    键值字典集合如何存储字符串键和指针值,指针可以是整数,字符串或对象。

    或者更具体。 &#34;价值&#34;可以是元组,其中第一个字段(可能是枚举类型)指示值的实际类型。并且,&#34;价值&#34;的第二个领域;是真实场的指针或变体。

    使用&#34; Unions&#34;的第一个建议(a.k.a。&#34; variants&#34;),没有指针:

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

    我已经看过这个&#34;模式&#34;好几次,我打电话给&#34; Key-Value-Type&#34;集合。

    注意:对STL的经验不多,你确定&#34; std :: map&#34;, 是正确的系列吗?

    只需2美分。

答案 2 :(得分:0)

可能不是你想要的,因为它是一种不同的方法,但你可以使用变体图。你可以定义boost::variant只保留字符串,int或float。

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