【问题标题】:Template function type casting at run time for json deserialization运行时用于 json 反序列化的模板函数类型转换
【发布时间】:2016-03-30 11:37:00
【问题描述】:

我想编写一个函数,将数组的 json 表示反序列化为 std::vector。我正在使用的 json 库是 Facebook 的愚蠢库的一部分。我想实现以下目标,但不幸的是它不起作用:

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

在上面的代码中,jsonField 是数组字段的表示。所以代码只是尝试循环遍历数组;然后对于每个元素;它将尝试推回通用向量:向量。问题是代码无法编译,因为它会抱怨它不能从 std::string 转换为 int;当 T=int;

我不确定如何编写这样的通用函数而不需要实现 4 个方法重载函数。 static bool deserializeHelper(std::string fieldName, vector& structField, const folly::dynamic& jsonObj) ....

谢谢。

【问题讨论】:

标签: c++11 casting json-deserialization template-function folly


【解决方案1】:

似乎下面的代码可以正常工作。我只是想知道是否有任何瓶颈、开销或以下工作正常:

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

基本上,它会先尝试转换为 void*,然后再从 void* 转换为 T*。我想知道是否可以改进。

谢谢。

【讨论】:

    【解决方案2】:

    执行此操作的两种类型安全的方法是:

    • 写4个方法,你已经拒绝了;和
    • if 语句中测试T

    可能看起来像这样:

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

    所有这些ifs 都将被静态评估,因此编译后的代码就像只有 used-branch 一样高效。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-03-04
      • 1970-01-01
      • 2015-10-26
      • 2016-11-29
      • 1970-01-01
      相关资源
      最近更新 更多