2015-10-11 23 views
5

Zacząłem od Boost.Hana i zastanawiałem się, czy istnieje sposób na deserializację z powrotem do struktury znanej Boost.Hana. Wiem, że to bardzo proste serializować taką Strukturę na przykład w łańcuchu json, ale nie znalazłem żadnych informacji na odwrót. Czy obecnie nie można deserializować danych za pomocą Boost.Hana lub czegoś brakuje?Czy można deserializować za pomocą Boost.Hana?

Odpowiedz

10

Hana jest biblioteką do metaprogramowania. Udostępnia narzędzia, których można użyć do budowania bardziej złożonych funkcji, takich jak serializacja, ale nie zapewnia takiej samej funkcjonalności. To po prostu nie zakres tej biblioteki. Ponadto, biorąc pod uwagę Twój konkretny przypadek użycia; parsowanie nie jest łatwym problemem, a inne biblioteki, takie jak Boost.Spirit, już próbują go rozwiązać.

Na tej podstawie nakreśliłem przykład użycia Hana do deserializacji JSON. Wynik nie jest ani wydajny, ani solidny, ale powinien wystarczyć, aby dać wgląd w to, jak Hana może zostać wykorzystana do osiągnięcia czegoś lepszego. Prawidłowe rozwiązanie tego problemu wymagałoby zaimplementowania biblioteki kombinatorowej parserów à-la Boost.Spirit, której nie zrobię tutaj. Proszę bardzo:

template <typename T> 
    std::enable_if_t<std::is_same<T, int>::value, 
T> from_json(std::istream& in) { 
    T result; 
    in >> result; 
    return result; 
} 

template <typename T> 
    std::enable_if_t<std::is_same<T, std::string>::value, 
T> from_json(std::istream& in) { 
    char quote; 
    in >> quote; 

    T result; 
    char c; 
    while (in.get(c) && c != '"') { 
     result += c; 
    } 
    return result; 
} 


template <typename T> 
    std::enable_if_t<hana::Struct<T>::value, 
T> from_json(std::istream& in) { 
    T result; 
    char brace; 
    in >> brace; 

    hana::for_each(hana::keys(result), [&](auto key) { 
     in.ignore(std::numeric_limits<std::streamsize>::max(), ':'); 
     auto& member = hana::at_key(result, key); 
     using Member = std::remove_reference_t<decltype(member)>; 
     member = from_json<Member>(in); 
    }); 
    in >> brace; 
    return result; 
} 

template <typename Xs> 
    std::enable_if_t<hana::Sequence<Xs>::value, 
Xs> from_json(std::istream& in) { 
    Xs result; 
    char bracket; 
    in >> bracket; 
    hana::length(result).times.with_index([&](auto i) { 
     if (i != 0u) { 
      char comma; 
      in >> comma; 
     } 

     auto& element = hana::at(result, i); 
     using Element = std::remove_reference_t<decltype(element)>; 
     element = from_json<Element>(in); 
    }); 
    in >> bracket; 
    return result; 
} 

I wtedy można go używać jak

struct Car { 
    BOOST_HANA_DEFINE_STRUCT(Car, 
     (std::string, brand), 
     (std::string, model) 
    ); 
}; 

struct Person { 
    BOOST_HANA_DEFINE_STRUCT(Person, 
     (std::string, name), 
     (std::string, last_name), 
     (int, age) 
    ); 
}; 

int main() { 
    std::istringstream json(R"EOS(
     [ 
      { 
       "name": "John", 
       "last_name": "Doe", 
       "age": 30 
      }, 
      { 
       "brand": "BMW", 
       "model": "Z3" 
      }, 
      { 
       "brand": "Audi", 
       "model": "A4" 
      } 
     ] 
    )EOS"); 

    auto actual = from_json<hana::tuple<Person, Car, Car>>(json); 

    auto expected = hana::make_tuple(Person{"John", "Doe", 30}, 
            Car{"BMW", "Z3"}, 
            Car{"Audi", "A4"}); 

    assert(actual == expected); 
} 

Pełne przykładem jest dostępny here.

+0

Dzięki, Louis. Próbowałem pisać do członków używając hana :: for_each (hana :: members (result), [] ...) bezskutecznie. Stworzyłeś niesamowitą bibliotekę! –