Приведение типов шаблонных функций во время выполнения для десериализации json
Я хочу написать функцию, которая десериализует 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
Благодарю.
2 ответа
Кажется, что код, как в следующих работах. Мне просто интересно, есть ли какие-нибудь узкие места, накладные расходы, или следующее прекрасно работает:
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*. Мне интересно, можно ли что-нибудь улучшить.
Благодарю.
Два типа безопасных способа сделать это:
- Напишите 4 метода, которые вы уже отклонили; а также
- Тестовое задание
T
вif
заявления.
Это может выглядеть примерно так:
#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;
}
Все из тех if
s будет оцениваться статически, поэтому скомпилированный код будет таким же эффективным, как если бы там была только ветвь used.