1

I want to write a function which deserialise a json representation of array into a std::vector. The json library which i am using is part of Facebook's folly library. I would like to achieve somethings like the following, but unfortunately it's not working:

template<typename T>
static bool deserializeHelper(std::string fieldName, vector< T >& structField, const folly::dynamic& jsonObj) {        
    if(auto* jsonField = jsonObj.get_ptr(fieldName)){
        if(jsonField->isArray()) {
           for(auto& elem : *jsonField) {
               if(elem.isInt()) {
                   structField.push_back(elem.asInt());
               } else if(elem.isString()){
                   structField.push_back(elem.asString());
               } else if(elem.isDouble()) {
                   structField.push_back(elem.asDouble());
               } else if(elem.isBool()) {
                   structField.push_back(elem.asBool());
               } else return false;
           }
        } else return false;
    }

    return true;
}

In the above code, jsonField is a representation of array field. So the code just try to loop through the array; then for each element; it will try to push back to generic vector: vector. The problem is that the code cannot be compiled because it will complain that it cannot cast from std::string to int; when T=int;

I am not sure how to write a generic function like that without the need of implement 4 method overloading functions. static bool deserializeHelper(std::string fieldName, vector< int >& structField, const folly::dynamic& jsonObj) ....

Thanks.

auxdx
  • 2,313
  • 3
  • 21
  • 25
  • Maybe using boost library's `boost::variant` type instead of a `std::vector` can help: http://www.boost.org/doc/libs/1_59_0/doc/html/variant.html – moonwalker Dec 24 '15 at 00:47

2 Answers2

0

Seems that code like in the following works. I am just wondering is there any bottleneck, overhead, or the following works just fine:

template<typename T>
static bool deserializeHelper(std::string fieldName, vector<T>& structField, const folly::dynamic& jsonObj) {
    if(auto* jsonField = jsonObj.get_ptr(fieldName)){
        if(jsonField->isArray()) {
            for(auto& elem : *jsonField) {
                if(elem.isInt()) {
                    int tmp = elem.getInt();
                    structField.push_back(*(static_cast<T*>(static_cast<void*>(&tmp))));
                } else if(elem.isString()){
                    std::string tmp = elem.getString().toStdString();
                    structField.push_back(*(static_cast<T*>(static_cast<void*>(&tmp))));
                } else if(elem.isDouble()) {
                    double tmp = elem.getDouble();
                    structField.push_back(*(static_cast<T*>(static_cast<void*>(&tmp))));
                } else if(elem.isBool()) {
                    bool tmp = elem.getBool();
                    structField.push_back(*(static_cast<T*>(static_cast<void*>(&tmp))));
                } else return false;
            }
        } else return false;
    }

    return true;
}

Basically, it will try to cast to void* first before doing another casting from void* to T*. I am wondering if anything could be improved.

Thanks.

auxdx
  • 2,313
  • 3
  • 21
  • 25
0

The two type-safe ways to do this are:

  • Write 4 methods, which you have already rejected; and
  • Test T in the if statements.

That could look something like this:

#include <type_traits>

template<typename T>
static bool deserializeHelper(std::string fieldName, vector< T >& structField, const folly::dynamic& jsonObj) {        
    if(auto* jsonField = jsonObj.get_ptr(fieldName)){
        if(jsonField->isArray()) {
           for(auto& elem : *jsonField) {
               if(std::is_same<T, bool>::value) {
                   structField.push_back(elem.asBool());
               } else if(std::is_convertible<int64_t, T>::value) {
                   structField.push_back(elem.asInt());
               } else if(std::is_convertible<std::string, T>::value){
                   structField.push_back(elem.asString());
               } else if(std::is_convertible<double, T>::value) {
                   structField.push_back(elem.asDouble());
               } else return false;
           }
        } else return false;
    }
    return true;
}

All of those ifs will be evaluated statically so the compiled code is as efficient as if only the used-branch were there.

Phil Willoughby
  • 1,649
  • 12
  • 16