2015-10-11 24 views
5

Ich beginne mit Boost.Hana und frage mich, ob es einen Weg gibt, um wieder in ein Struct zu deserialisieren, das Boost.Hana bekannt ist. Ich weiß, es ist ziemlich einfach, ein solches Struct in eine JSON-Zeichenfolge zu serialisieren, aber ich habe keine Information darüber gefunden. Ist es derzeit einfach nicht möglich, Daten mit Boost.Hana zu deserialisieren oder fehlt mir etwas?Ist es möglich, mit Boost.Hana zu deserialisieren?

Antwort

10

Hana ist eine Metaprogrammierungsbibliothek. Es bietet Tools, die verwendet werden können, um komplexere Funktionen wie Serialisierung zu bauen, aber es bietet keine solche Funktionalität selbst. Es ist einfach nicht der Umfang dieser Bibliothek. Auch in Bezug auf Ihren speziellen Anwendungsfall; Parsing ist kein einfaches Problem und andere Bibliotheken versuchen, Boost.Spirit bereits zu lösen.

Das skizzierte ich skizzierte ein Beispiel der Verwendung von Hana zum Deserialisieren von JSON. Das Ergebnis ist weder effizient noch robust, aber es sollte reichen, um Ihnen einen Einblick zu geben, wie Hana verwendet werden könnte, um etwas Besseres zu erreichen. Solving dieses Problem korrekt würde erfordern, eine Parser-Kombinator-Bibliothek à-la Boost.Spirit implementieren, die ich hier nicht tun werde. Hier gehen Sie:

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

Und dann kann man es verwenden, wie

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

Das vollständige Beispiel ist here verfügbar.

+0

Danke, Louis. Ich habe versucht, an Mitglieder zu schreiben, indem ich hana :: for_each (hana :: members (result), [] ...) nutzlos benutzte. Sie haben eine erstaunliche Bibliothek erstellt! –

Verwandte Themen