【问题标题】:Storing multiple types in map在地图中存储多种类型
【发布时间】:2023-03-31 05:58:01
【问题描述】:

我想在地图中存储多种类型的对象,我想出了这个解决方案。我必须知道每个对象的类型,所以我不能使用 boost::any。有没有更好的方法来做到这一点,或者这是一个可以接受的解决方案?

enum eType
{
    TYPE_STRING,
    TYPE_NUMBER,
};

class CType
{ 
public:
    int GetType() { return m_Type; }

protected:
    int m_Type;
};

template <typename T>
class CData : public CType
{
public:
    CData(const T & rData, int iType)
    {
        m_Type  = iType;
        m_Data  = rData;
    }

    T & GetData() { return m_Data; }

private:
    T m_Data;
};

std::map<unsigned long, CType *> map_Data;

void main()
{
    // Create a new data with TYPE_NUMBER
    CData<short> data(32767, TYPE_NUMBER);

    // Add it to the map
    map_Data[0] = &data;

    // Get the type
    switch (map_Data[0]->GetType())
    {
        case TYPE_NUMBER:
        {
            // Cast the first element to CData
            CData<short> * pField = (CData<short> *)map_Data[0];

            // Print the data
            printf("Data: %d\n", pField->GetData());
        }
        break;

        case TYPE_STRING:
        {
            // Cast the first element to CData
            CData<std::string> * pField = (CData<std::string> *)map_Data[0];

            // Print the data
            printf("Data: %s\n", pField->GetData().c_str());
        }
        break;
    }
}

【问题讨论】:

标签: c++ templates stl containers std


【解决方案1】:

使用boost::anyboost::any_cast

检查 any 是否为 int;

bool is_int(const boost::any & operand)
{
    return operand.type() == typeid(int);
}

检查是否为const char *

bool is_char_ptr(const boost::any & operand)
{
    try
    {
        any_cast<const char *>(operand);
        return true;
    }
    catch(const boost::bad_any_cast &)
    {
        return false;
    }
}

【讨论】:

    【解决方案2】:

    如果您不想使用 getType 之类的函数污染您的类,一个基本且易于使用的解决方案是使用如下示例中的标记联合:

    #include <map>
    
    struct StructA { };
    struct StructB { };
    
    struct TaggedUnion {
        enum { A, B } tag;
        union {
            StructA a;
            StructB b;
        };
    };
    
    int main() {
        std::map<std::size_t, TaggedUnion> map;
        map[0] = TaggedUnion{ TaggedUnion::A, StructA{} };
    
        switch(map[0].tag) {
        case TaggedUnion::A:
            // do whatever you want with map[0].a;
            // ...
            break;
        case TaggedUnion::B:
            // do whatever you want with map[0].b
            // ...
            break;
        }
    }
    

    【讨论】:

      【解决方案3】:

      您的问题很有趣,我不明白为什么如此不赞成。不幸的是,您尝试做的事情在 C++ 中是不可能的(我想知道在 Java 或 C# 中是否可行)

      我再次提出我认为是您问题核心的链接。

      creating-an-interface-for-an-abstract-class-template-in-c++

      除此之外,您的实现很有趣。我只是在这里进行了一些返工,因为我认为您可以在没有讨厌的开关盒的情况下节省一些行:

      #include <iostream>
      #include <string>
      #include <sstream>
      #include <List>
      
      using namespace std;
      
      struct CType
      {
          int GetType() { return m_Type; }
          string GetStringVal() { return m_string_val; }
          enum eType {     TYPE_STRING,
                           TYPE_NUMBER };
      protected:
          int m_Type;
          string m_string_val;
      };
      
      template <typename T>
      class CData : public CType
      {
      public:
          CData(const T & rData):m_Data(rData)
          {
              stringstream strs;
              m_Type  = GetType();
              //Mingw bug
              //m_string_val = std::to_string(m_Data); //c++11
              strs << m_Data;
              m_string_val = strs.str();
          }
      
          T & GetData() { return m_Data; }
      
      private:
          T m_Data;
          CType::eType GetType();
      };
      
      template<> CType::eType CData<int>::GetType() { return TYPE_NUMBER; };
      template<> CType::eType CData<string>::GetType() { return TYPE_STRING; };
      //More specialization here
      
      int main()
      {
          cout << "Hello world!" << endl;
      
          CData<int> cd_int(5);
          CData<string> cd_str("SO contribution");
      
          list<CType> my_list = { cd_int, cd_str };
      
          for ( auto & elem : my_list)
              cout << elem.GetStringVal() << endl;
      
          return 0;
      }
      

      结果自然是:

      世界你好!

      5

      SO 贡献

      -----添加 2016 年 9 月 5 日-----

      另一种可能性是存储返回结果而不是结果本身的函数(带有“this”捕获的 lambda)。避免在 m_Data 字段更改时执行更新

      #include <iostream>
      #include <string>
      #include <sstream>
      #include <List>
      #include <functional>
      
      using namespace std;
      
      struct CType
      {
          int GetType() { return m_Type; }
          string GetStringVal() { return m_string_func(); }
          enum eType {     TYPE_STRING,
                           TYPE_NUMBER };
      protected:
          int m_Type;
          function<string()> m_string_func ;
      };
      
      template <typename T>
      class CData : public CType
      {
          public:
          CData(const T & rData):m_Data(rData)
          {
              m_Type  = GetType();
              m_string_func = [this](){   //MinGW bug,otherwise to_string()
                                          stringstream strs;
                                          strs << m_Data;
                                          return strs.str();};
          }
      
      private:
          T m_Data;
          CType::eType GetType();
      };
      
      template<> CType::eType CData<int>::GetType() { return TYPE_NUMBER; };
      template<> CType::eType CData<string>::GetType() { return TYPE_STRING; };
      
      int main()
      {
          cout << "Hello world!" << endl;
      
          CData<int> cd_int(5);
          CData<string> cd_str("SO contribution");
      
          list<CType> my_list = { cd_int, cd_str };
      
          for ( auto & elem : my_list)
              cout << elem.GetStringVal() << endl;
      
          return 0;
      }
      

      【讨论】:

        猜你喜欢
        • 2013-08-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-09-08
        • 1970-01-01
        • 2018-08-16
        • 2012-12-15
        相关资源
        最近更新 更多