简体   繁体   中英

C++: How to create multi-type and multi-dimensional array format?

I'm trying to read similar array format as PHP uses:

"data" => array(
    "keyname1" => "string", 
    "somearraykeyname" => array(
        "keyname1" => "more strings", 
        "keyname2" => "bla bla", 
        "moar" => array(
            "first" => 1, 
            "second" => 2, 
            "third" => "3",
        ),
        "keyname3" => 25,
    ), 
    "keyname2" => 13.37, 
    "keyname3" => 1337, 
    "array without keynames" => array(
        "keke", 
        "lala", 
        "lolo",
    ),
);

But i stumbled upon on the multiple possible types problem. How can this done in C++ the best way ?

I was thinking to create a struct with all possible types for each element:

struct GeneralType {
    char WhichType; // which type we are using for this value
    int IntVal;
    float FloatVal;
    string StringVal;
};

And when i read an element, i will decide by the value which type it will get, and then convert the value to correct type and set it to the correct variable (IntVal, FloatVal or StringVal). Also i will keep track which type the value is currently using with WhichType variable, so i can easily pick the correct variable when i use the value.

Is this anywhere near a good approach?

Also, theres another problem; how can i define std::vector without knowing the depth of the array beforehand? i could type vector<vector<GeneralType> > if each element always was an array itself. But not all elements are arrays. So, i dont know how to solve this with std::vector. Is it even possible ?

First idea i had, was to simply just make the key sequence into a string that is stored in an std::map key, where the std::map value would be GeneralType type, and this way i would be able to define any dimensional easily, and also get the value i want quickly, something like this:

Mymap["data/somearraykeyname/moar"] = GeneralTypeValue; // this value not used, it will be a marker only, so i can get the first item position in the std::map easily.
Mymap["data/somearraykeyname/moar/first"] = GeneralTypeValue; // array "moar" key "first" value.

But this method prevents me from quickly looping through all the elements from a specific array. Although, the keys are sorted, so i should have the correct order always; but, it would require me to parse the key each time, and check if the array changed at next element. This could work, but not very efficiently.

What other ideas could there be for this?

Edit: I also want to be able to call an N-dimension array like: array["data"]["somearraykeyname"]["moar"]["first"] And then if the value type is array, i could be able to loop the array as if it was vector of GeneralType

Use a boost::variant. It will remember the type inside it itself and is pretty easy to use.

You should consider using a boost::any , which can hold any data type.

If you want your elements to contain arrays themselves, you can wrap a std::vector in a boost::any , and check when you access the elements of your array, if they are themselves arrays.

使用union,而不是struct,这就是它的用途。

struct GeneralType { };

struct IntType : public GeneralType { int IntVal; };
struct FloatType : public GeneralType { float FloatVal; };
struct StringType : public GeneralType { string StringVal; };

vector<GeneralType*> vec;
vec.push_back(new IntType);
vec.push_back(new FloatType);
vec.push_back(new StringType);

for (int i=0; i<3; ++i)
{
 IntType* type = dynamic_cast<IntType>(vec[i]);
 if (type != 0)
 {
 // using type->IntVal
 }
 else
 {
  FloatType* type = dynamic_cast<FloatType>(vec[i]);
  if (type != 0)
  {
   // using type->FloatVal
  }
  else
  {
   StringType* type = dynamic_cast<StringType>(vec[i]);
   if (type != 0)
   {
   // using type->StringVal
   }
  }
 }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM